密码验证方案

3.3  密码验证方案

在一些保密性较高的管理软件中,为了不让非操作员进入系统,对操作员的用户名及密码进行加密是十分重要的,那么,如何对其进行加密呢?本节将用算数加密法和SQL Server自带的加密方法对用户名和密码进行加密,以防止非操作员通过数据库中的用户数据表进入系统。

3.3.1  算数加密

算数加密方法实际上是以特定的计算方式,将用户名和密码进行加密,并存入到数据库中,在验证密码时,将数据库中的用户名和密码以相反的计算方式恢复到原来的数据信息,并与输入的信息进行比较。使用这种方式,在用户数据表中所看到的信息只是变形后的数据,无法用它来进行登录。

1.方案分析

算数加密方法在这里实际上是以指定的十六进制值,将用户名和密码进行异或运算,并存储到数据库中。这样,就无法在数据库中看到正确的信息。在用正确的用户名和密码与数据库中的信息进行比较时,先以指定的十六进制值将数据库中的用户名和密码进行恢复,然后再进行比较。下面给出算数密码加密的流程图,如图3.34所示。

图3.34  算数密码加密的流程图

在制作算数密码加密方案时,主要有以下几个难点:

(1)如何对用户名及密码进行加密。

(2)如何对用户名及密码进行解密。

(3)在清空用户表信息后,自动添加默认用户名及密码。

2.实施过程

为了能够确保操作员信息的保密性,可以根据自已设置的十六进制数对操作员信息进行加密,在这里只对密码进行加密。下面就介绍算数密码加密的制作过程。

*    实例位置:光盘\mr\3\3.3\3.3.1\01

本方案实现的“登录”窗体如图3.35所示。

图3.35  “登录”窗体

在制作本方案前,首先要在数据库中制作一个用户表(tb_C_User),该表记录了本系统的合法用户名和密码。用户表的关系图如图3.36所示。

图3.36  tb_C_User数据表的关系图

在用指定的十六进制数对密码进行加密,加密后的字符串将超出原来密码的长度,所以,在创建用户表(tb_C_User)时,尽量将密码的长度设的大一些。

下面对密码的加密和解密的过程进行详细的说明。

本方案中的“登录”窗体、“主界面”窗体和“操作员管理”窗体,与3.2.1节中的窗体布局及设置基本相同,在这里只对密码的加密和解密的应用方法进行说明。

该方案先对“操作员管理”窗体进行设置,通过该窗体先在用户数据表中添加一个加密后的用户信息。如图3.37所示。

图3.37  “操作员管理”窗体

该窗体在“保存”按钮中,对添加或修改的用户密码进行加密后,存入到用户数据表中。“保存”按钮的操作代码如下:

procedure TFrm_AddUser.ToolButton4Click(Sender: TObject);

begin

  ADDUserInfo(DataModule1.ADOQuery2,AddAmend,Edit1,Edit2);

  EnabledTF(ToolButton4,True,False);

  DataModule1.ADO_user.Active := False;

  DataModule1.ADO_user.Active := True;

end;

自定义过程ADDUserInfo(),用于将加密后的密码和用户名存入到数据库中。代码如下:

procedure TFrm_AddUser.ADDUserInfo(ADOQuer: TADOQuery; n: Integer; E1,E2 : TEdit);

begin

  with ADOQuer do

  begin

    Close;

    SQL.Clear;

    SQL.Add('select * from tb_C_User where ID='+

IntToStr(DataModule1.ADO_user.fieldbyname('ID').AsInteger));

    Open;

    if n=1 then

      Insert

    else if n=2 then

      Edit

    else

    begin

      Exit;

    end;

    FieldByName('User_Name').AsVariant :=Trim(E1.Text);

    FieldByName('User_Pass').AsVariant :=Encrypt(Trim(E2.Text));

    Post;

  end;

end;

ADDUserInfo()过程的参数说明如表3.11所示。

表3.11                           ADDUserInfo()过程的参数说明

参数

说明

ADOQuer

TADOQuery类型,按指定条件获取数据表中的信息

n

标识,当n=1时,表示插入信息;当n=2时,表示修改信息

E1,E2

TEdit类型,用于获取TEdit组件的信息

自定义过程Encrypt(),用于对指定的数据库进行加密。代码如下:

function TFrm_AddUser.Encrypt(Str: String): String;

var

  i,j:Integer;

begin

  Result:='';

  j:=0;

  for i:=1 to Length(Str) do

  begin

    Result:=Result+IntToHex(Byte(Str[i]) xor decipher[j],2);

    j:=(j+1) mod length(decipher);

  end;

end;

参数Str:要进行加密的字符串。

返回值:返回一个加密后的字符串。

在Encrypt()过程中,将字符串中的每个字符,按字符的位置分别与字节数组中相应索引号的十六进制数进行异或运算得到一个整数值,然后利用IntToHex函数,将该整数值转换成2位字符串,并通过循环,将转换后的字符串进行连接,形成加密后的字符串。

为了方便定义和设置字节数组decipher的值,可以将其设为一个全局数组,并同时进行赋值。代码如下:

var

  decipher:array[0..9] of Byte=($90,$AF,$A6,$00,$3E,$AB,$77,$4B,$FE,$D1);

 

implementation

以上就完成了对操作员密码进行加密的过程。

下面讲解一下如何对操作员密码进行解密。对密码进行解密,实际上就是在操作员登录的同时,对数据库中的相应操作员密码进行解密,然后再判断是否相同,如果相同,则进行入主界面,否则,密码输入错误。

在“登录”窗体中输入正确的用户名和密码,单击“登录”按钮进行登录,在该按钮的OnClick事件中,在用户数据表(tb_C_User)中查找与用户名相同的记录,获取该记录中的密码信息,将其解密后与“登录”窗体中的密码信息进行比较,如果相同则进行主界面,否则,重新输入。代码如下:

procedure TFrm_Enter.SpeedButton1Click(Sender: TObject);

begin

  with DataModule1.ADO_user do

  begin

    close;

    SQL.Clear;

    SQl.Add('select * from tb_C_User where User_Name='+''''+Edit1.Text+'''');

    Open;

  end;

  if Explain(DataModule1.ADO_user.FieldByName('User_Pass').AsString) =

Trim(Edit2.Text) then  //将数据库中的密码解密后与登录密码进行比较

  begin

    ifclose := 1;

    close;

  end

  else

  begin

    showmessage('操作员名称、密码或操作员级别不正确'+#13+'请重新输入。');  //换行显示提示信息

    Edit1.Clear;

    Edit2.Clear;

  end;

end;

自定义过程Explain(),将加密后的字符串进行解密。代码如下:

function TFrm_Enter.Explain(Str: String): String;

var

  i,j:Integer;

begin

  Result:='';

  j:=0;

  for i:=1 to Length(Str) div 2 do

  begin

    Result:=Result+Char(StrToInt('$'+Copy(Str,i*2-1,2)) xor decipher[j]);

    j:=(j+1) mod length(decipher);

  end;

end;

参数Str:加密后的字符串。

返回值:返回解密后的字符串。

  注意:在Explain()过程中的字节数组decipher必需与Encrypt()过程中的字节数组decipher相同。

3.补充说明

对字符串加密的方式有很多种,下面介绍一个用数字和ASCII码进行异或加密/解密的算法,该方法只能对字母和数字进行加密。

对字符串进行加密和解密的代码如下:

自定义过程Encrypt(),用于将字符串以指定的数字进行加密,S表示要加密的字符串,n表示进行加密计算的数字。该过程将返回一个加密后的字符串。

function Encrypt(S: string; n : Integer): string;

var

  s1,s2:String;

  i,j,k:integer;

begin

  s1:=trim(S);

  k:=round(length(s1)/2+0.0001);

  s2:=s1;

  j:=1;

  for i:=1 to k do

  begin

    if chr(ord(s1[i]) xor n) IN ['0'..'9','a'..'z','A'..'Z'] then

      s2[j]:=chr(ord(s1[i]) xor n)

    else

      s2[j]:=s1[i];

    inc(j);

    if j<=length(s1) then

    begin

      if chr(ord(s1[i+k]) xor n) IN ['0'..'9','a'..'z','A'..'Z'] then

        s2[j]:=chr(ord(s1[i+k]) xor n)

      else

        s2[j]:=s1[i+k];

      inc(j);

    end;

  end;

  result:=s2;

end;

自定义过程Decript(),用于将加密的字符串以指定的数字进行解密,S表示要解密的字符串,n表示进行解密计算的数字。该过程将返回一个解密后的字符串。

function Decript(S : string; n : Integer): string;  //解密

var

  s1,s2:String;

  i,j,k:integer;

begin

  s1:=trim(S);

  s2:=s1;

  i := 1;

  j := 1;

  while i <= Length(s1) do

  begin

    s2[j] := chr(ord(s1[i]) xor n);

    if not (s2[j] in ['0'..'9','a'..'z','A'..'Z']) then

      s2[j] := chr(ord(s2[j]) xor n);

    inc(i, 2);

    inc(j);

  end;

  i := 2;

  while i <= Length(s1) do

  begin

    s2[j] := chr(ord(s1[i]) xor n);

    if not (s2[j] in ['0'..'9','a'..'z','A'..'Z']) then

      s2[j] := chr(ord(s2[j]) xor n);

    inc(i, 2);

    inc(j);

  end;

  result:=s2;

end;

要想用以上两个过程对同一个字符串进行加密或解密操作,这两个过程的参数n值必须相同。

3.3.2  SQL Server加密

在数据库信息共享时,很容易就能看到数据表中的信息,使数据库的安全性大大降低。这时,可以根据数据库自带的加密技术对数据表中的数据进行加密,以确保数据的安全性。本节将主要讲解用数据库加密技术对操作员信息进行加密的过程。

1.方案分析

在这里的SQL Server加密技术,实际上是用SQL函数pwdencryp()对存入数据库中的信息进行加密,本方案是将加密和解密的过程封装到存储过程中,通过调用存储过程来实现操作员密码的加密。下面是SQL Server加密的流程图。如图3.38所示。

图3.38  SQL Server加密的流程图

在制作算数密码加密方案时,主要有以下几个难点:

(1)如何用SQL函数对数据进行加密或解密。

(2)如何将加密和解密的过程封装到带有参数及返回值的存储过程中。

(3)如何在程序中使用定义后的存储过程。

2.实施过程

使用SQL Server中的加密函数对数据进行加密,难以被其他人所破译,可以使数据的保密度得到提高。下面就介绍SQL Server加密操作员密码的制作过程。

*    实例位置:光盘\mr\3\3.3\3.3.2\01

本方案实现的“登录”窗体如图3.39所示。

图3.39  “登录”窗体

在制作本方案前,首先要在数据库中制作一个用户表(tb_S_UsetEnter),该表记录了本系统中合法用户名及被加密后的密码。用户表的关系图如图3.40所示。

图3.40  tb_S_UsetEnter数据表的关系图

在用SQL函数pwdencryp()对字符串进行加密后,所返回的格式是二进制数,所以要将用户数据表中的User_Pass字段设为varbinary类型,并将长度设置大一些(见意长度设置成500)。

然后在数据库(MR_Distribution)中的存储过程中创建两个存储过程Pro_Encrypt和Pro_DispelPass。

存储过程Pro_Encrypt用于对传入的字符串进行加密。代码如下:

CREATE PROCEDURE Pro_Encrypt

@Str varchar(20),  --要进行加密的字符串

@ret varbinary(500) output  --返回参数,用于存贮加密后的二进制数

AS

SET @ret=(pwdencrypt(@Str))  --对字符串进行加密

print @ret

GO

存储过程Pro_DispelPass将传入的用户登录密码和数据库中已加密的登录密码进行比较,如果返回1,表示密码相同,返回0,表示登录密码错误。代码如下:

CREATE PROCEDURE Pro_DispelPass

@Password VARCHAR(20),  --登录密码

@Treeno VARCHAR(20),  --用户名

@return int output  --返回值

AS

begin

  select @return=Pwdcompare(@Password,User_Pass) From tb_S_UsetEnter Where

User_Name=@Treeno  --比较数据库中的密码和登录密码是否相同

  select @return  --返回比较值

end

GO

下面就对SQL Server加密在程序中的应用进行详细说明。

本方案中的“登录”窗体、“主界面”窗体和“操作员管理”窗体,与3.2.1节中的窗体部局及设置基本相同,在这里只对存储过程Pro_Encrypt和Pro_DispelPass的应用方法进行说明。

该方案先对“操作员管理”窗体进行设置,通过该窗体先在用户数据表中添加一个加密后的用户信息。如图3.41所示。

图3.41  “操作员管理”窗体

该窗体在“保存”按钮中,对添加或修改后的用户密码用存储过程Pro_Encrypt进行加密,并将结果存入到用户数据表中。“保存”按钮的操作代码如下:

procedure TFrm_AddUser.ToolButton4Click(Sender: TObject);

begin

  with DataModule1.ADOStoredProc1 do  //用ADOStoredProc1组来执行存储过程

  begin

    ProcedureName := 'Pro_Encrypt';  //添加要执行存储过程的名称

    close;

    Parameters.Clear;

    Parameters.CreateParameter('@Str',ftString,pdInput,20,'');  //创建参数

    Parameters.CreateParameter('@ret',ftVarBytes,pdOutput,100,'');  //创建参数

    parameters.parambyname('@Str').Value:=Trim(Edit2.Text);  //向参数中传值

    prepared:=true;

    ExecProc;  //执行存储过程

  end;

  with DataModule1.ADOQuery2 do

  begin

    Close;

    SQL.Clear;

    SQL.Add('select * from tb_S_UsetEnter where ID='+IntToStr

(DataModule1.ADO_user.fieldbyname('ID').AsInteger));

    Open;

    if AddAmend=1 then

      Insert

    else if AddAmend=2 then

      Edit

    else

    begin

      Exit;

    end;

    FieldByName('User_Name').AsVariant :=Trim(Edit1.Text);

    FieldByName('User_Pass').AsVariant :=DataModule1.ADOStoredProc1

.Parameters.ParamByName('@ret').Value;  //将存储过程加密后的二进制值存入到数据表中

    Post;

  end;

  EnabledTF(ToolButton4,True,False);

  DataModule1.ADO_user.Active := False;

  DataModule1.ADO_user.Active := True;

end;

下面讲解一下如何在“登录”窗体中利用存储过程Pro_DispelPass对密码进行判断,查看输入密码是否正确。

在“登录”窗体中输入正确的用户名和密码,单击“确定”按钮进行登录,在该按钮的OnClick事件中,用存储过程Pro_DispelPass在用户数据表(tb_S_UsetEnter)中查找与用户名相同的记录,并用SQL函数判断输入的密码是否与数据库中的加密密码相同,如果相同,则登录成功,否则,登录失败。代码如下:

procedure TFrm_Enter.BitBtn1Click(Sender: TObject);

begin

  with DataModule1.ADOStoredProc1 do

  begin

    ProcedureName :=  'Pro_DispelPass';  //添加要执行存储过程的名称

    close;

    Parameters.Clear;

    Parameters.CreateParameter('@Password',ftString,pdInput,20,'');  //创建参数

    Parameters.CreateParameter('@Treeno',ftString,pdInput,20,'');  //创建参数

    Parameters.CreateParameter('@return',ftInteger,pdReturnValue,0,0);  创建参数

    parameters.parambyname('@Password').Value:=Trim(Edit2.Text);  //向参数中传值

    parameters.parambyname('@Treeno').Value:=Trim(Edit1.Text);  //向参数中传值

    prepared:=true;

    ExecProc;  //执行存储过程

  end;

  //如果存储过程返回1,则表示密码正确

  if DataModule1.ADOStoredProc1.Parameters.ParamByName('@return').Value=1 then

  begin

    ifclose := 1;

    close;

  end

  else

  begin

    showmessage('操作员名称、密码或操作员级别不正确'+#13+'请重新输入。');

    edit1.Clear;

    edit2.Clear;

  end;

end;

3.补充说明

在备份数据库时,为了防止其他人通过备份文件盗取数据库中的信息,可以在备份时对备份文件进行加密,SQL语句如下:

  --备份:

  BackUp DataBase 数据库名 to Disk= 'c:\a.bak' with PASSWORD ='mingrisoft', init

  --恢复:

  Restore DataBase 数据库名 from Disk = 'c:\a.bak' with PASSWORD='mingrisoft'

在数据库的存储过程中可能包含所有者的商业信息,但是这些信息是不能被其他人看到的,这时,就应该对存储过程进行加密,以确保安全性。使用格式如下:

CREATE PROCEDURE PRO_Secrecy

@Parameter as varchar(10)      --定义参数

WITH ENCRYPTION  //对存储过程进行加密

AS

--存储过程语句

GO

  注意:在用WITH ENCRYPTION语句对存储过程加密后,该存储过程将无法再打开。

转载于:https://www.cnblogs.com/wenwencao/archive/2008/12/30/1365321.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值