本文主要是介绍PB应用的数据库联接的安全防范,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
随着因特网的深入人心,网络技术不断发展,数据的保密性要求也越来越高。在通常的Server/Client方式MIS开发中,由于程序要与数据库服务器保持联接,为了程序的灵活和扩充性,联接参数(用户ID和登录口令)又不能在程序中写死(其实写死也不是一种好的方法),一般的方法无外乎有两种:其一是把联接参数存放在注册表中;其二就是直接读INI文件。
而综上几种方法安全性都不太好,给人以可乘之机。
本人找到一种方法,可以解决数据库应用的安全性问题,通过INI文件和数据库的巧妙处理,在程序中提供用户一种接口,可以随时修改数据库的联接参数,而又不给外人以蛛丝马迹,做到神不知鬼不觉。
实现方法如下:
1、创建INI文件,记录数据库联接的一些方便程序分发的参数DBMS、SERVERNAME、LOGID具体如下:
//创建成INI文件(rsgl.ini)
[Database]
DBMS=O84 ORACLE 8.0.4
ServerName=gxmistest //数据库服务器名
LogId=rsgl //实际的数据库登录用户
然后,在数据库中创建一个中间用户PUB,登录口令PUB,赋予PUB用户CONNECT,RESOURCE权限,再在其中创建表CREATE TABLE TBL_PUB_PASSSHADOW (PASSSHADOW VARCHAR2(50) NOT NULL)用于存放实际的数据库联接的登录口令(当然要经过加密)。加密函数网上多的是,在此就不累述。我自已创建了一个字符串加密函数f_password(string old_str,string new_str,integer jm_mode),jm_mode参数用以区分函数的加(解)密,old_str、new_str两参数分别为加(解)密的字符串。
-- 创建登陆,无密码策略,密码不过期
CREATE LOGIN [test_l] WITH PASSWORD='pwd1213',DEFAULT_DATABASE=[db_1], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF;
GO
USE db_1;
GO
-- 创建用户
CREATE USER [test_u] FROM LOGIN [test_l];
GO
-- 授权
GRANT SELECT ON dbo.table1 TO [test_u];
GO
2、就开始编写应用程序了,在应用程序的OPEN事件中进行数据库登录联接,程序脚本如下:
string ls_inifile,ls_starttimes
string ls_logid,ls_logpass,ls_dbms
string ls_pass,ls_sql,ls_code,ls_server
//设置INI文件
ls_inifile = 'rsgl.ini'
ls_server = ProfileString (ls_inifile, "database", "ServerName", "")
ls_logid = ProfileString (ls_inifile, "database", "LogId","")
// Profile pub
SQLCA.DBMS = ProfileString (ls_inifile, "database", "dbms", "")
SQLCA.LogPass = 'pub'
SQLCA.ServerName = ls_server
SQLCA.LogId = "pub"
SQLCA.AutoCommit = False
SQLCA.DBParm = ""
connect using sqlca;
//得到用户RSGL加过密的用户口令
select passshadow into:ls_pass from tbl_pub_passshadow;
//口令解密
ls_pass = f_password(ls_pass,0)
disconnect using sqlca;
//联接到实际的数据库用户RSGL
SQLCA.ServerName = ls_server
sqlca.DBMS = ProfileString (ls_inifile, "database", "Dbms","")
SQLCA.DBParm = ProfileString (ls_inifile, "database", "Dbparm","")
sqlca.database = ProfileString (ls_inifile, "database", "database","")
sqlca.userid = ProfileString (ls_inifile, "database", "userid","")
sqlca.dbpass = ProfileString (ls_inifile, "database", "dbpass","")
sqlca.logid = ls_logid
sqlca.logpass = ls_pass//ProfileString (ls_inifile, "database", "LogPass","")
SQLCA.AutoCommit = False
connect using sqlca;
if sqlca.sqldbcode <> 0 then
choose case sqlca.sqldbcode
case 1017
MessageBox (string(sqlca.SQLDBCode),"不能联接数据库。~r错误:无效的用户名和口令.请与管理员联系!")
case 12154
MessageBox (string(sqlca.SQLDBCode),"不能联接数据库。~r错误:服务器名不存在!请与系统管理员联系.")
case 999
MessageBox (string(sqlca.SQLDBCode),"不能联接数据库。~r错误:数据库不支持你当前的安装!")
case else
MessageBox (string(sqlca.SQLDBCode),"不能联接数据库。~r错误:"+ sqlca.sqlerrtext)
end choose
halt close
else
open(w_gd_frame) //打开应用程序的主窗口
end if
3、接下来,就是编写一个用户接口,让授权用户随时修改数据库联接参数。窗口界面见下图:(文件名称:dblogon.jpg),窗口上面的控件有:
控件名称 控件属性
sle_server SingleLineEdit
sle_login SingleLineEdit
sle_oldkl SingleLineEdit
sle_pass SingleLineEdit
sle_repass SingleLineEdit
cb_1 commandbutton
cb_2 commandbutton
cb_1命令按钮的clicked事件如下:
string ls_inifile,ls_pass,ls_logid,ls_repass,ls_old
string ls_k,ls_user,ls_sql
ls_inifile ='rsgl.ini'
transaction pub_tr
pub_tr = create transaction
pub_tr.DBMS = ProfileString (ls_inifile, "database", "dbms", "")
pub_tr.LogPass = 'pub'
pub_tr.ServerName = sle_server.text
pub_tr.LogId = "pub"
pub_tr.AutoCommit = False
pub_tr.DBParm = ""
connect using pub_tr;
ls_old = sle_oldkl.text
ls_user = lower(trim(sle_logid.text))
//得到数据库联接原用户口令
select passshadow into :ls_k from tbl_pub_passshadow using pub_tr;
if ls_old <> f_password(ls_k,0) then
messagebox("提示","原口令不对!")
return
end if
//检查核对口令
ls_pass = sle_pass.text
ls_repass = sle_repass.text
if ls_repass <> ls_pass then
messagebox("","核对口令不对,请重新输入!")
return
end if
SetProfileString(ls_inifile, "Database", "Servername",sle_server.text)
SetProfileString(ls_inifile, "Database", "Logid",ls_user)
//修改数据库用户的联接口令
ls_sql = ' alter user '+ls_user+' identified by '+ls_pass
Execute Immediate :ls_sql using sqlca;
ls_pass = f_password(ls_pass,1)
UPDATE TBL_PUB_PASSSHADOW SET PASSSHADOW =:ls_pass using pub_tr ;
commit using pub_tr;
commit using sqlca;
disconnect using pub_tr;
close(parent)
cb_2命令按钮的clicked事件如下:close(parent)
4、到此万事OK。
所有代码已在Win98环境下,用PowerBuilder 6.5测试通过。
附:解密源代码
/*******************************************************************
函数名称:f_decryptpbpassword()
参数: as_orginalpassword string 原始密码
返回值: string 解密后文本
功能描述:解密PB数据库连接描述密码
创建人: 康剑民
创建日期:2006-04-27
版本号: V1.0
*******************************************************************/
string ls_temp,ls_return=''
integer i,li_count,li_ascii
nvo_numerical lnv_numerical
if len(as_orginalpassword) < 2 or as_orginalpassword = '00' then return ''
as_orginalpassword = left(reverse(as_orginalpassword),len(as_orginalpassword) - 2)
li_count = ceiling(len(as_orginalpassword) / 2)
for i = 1 to li_count
ls_temp = mid(as_orginalpassword,(i - 1) * 2 + 1,2)
li_ascii = lnv_numerical.of_hextodecimal(ls_temp)
ls_temp = char(li_ascii)
ls_return = ls_return + ls_temp
next
return ls_return
/*******************************************************************
函数名称:of_hextodecimal()
参数: as_hexdata string 16进制数据
返回值: unsignedlong 10进制数据
功能描述:16进制数据转为10进制数据
创建人: 康剑民
创建日期:2006-04-27
版本号:V1.0
*******************************************************************/
char lch_char[]
unsignedlong lul_decimal=0
integer li_dec[48 to 70], i, li_len
for i = 48 To 57
li_dec[i] = i - 48
next
for i = 65 To 70
li_dec[i] = i - 55
next
as_hexdata = lower(as_hexdata)
lch_char = as_hexdata
li_len = len (as_hexdata)
for i = 1 to li_len
choose case lch_char[i]
case '0' to '9', 'a' to 'f'
lul_decimal = lul_decimal * 16 + li_dec[asc(lch_char[i])]
case else
return lul_decimal
end choose
next
return lul_decimal
写作日期:2006-05-15
这篇关于PB应用的数据库联接的安全防范的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!