SAS中的ODBC密码安全性

Rob*_*dge 5 security odbc sas password-protection

我们希望从SAS代码中的ODBC连接字符串中删除硬编码的密码,并且还希望避免任何密码出现在SAS日志文件中。

似乎有很多白皮书讨论如何解决此问题,但是我要么发现它们有问题,要么无法使其工作。

每次提示用户输入PW都不可行。同样,将密码存储在宏变量中也是可以接受的方法,只要您有一种方法可以在打开MACROGEN和SYMBOLGEN选项的情况下禁止将其打印到日志中。

尝试1-编码在此处链接至白皮书

proc pwencode in='mypassword' method=sasenc;
run;
Run Code Online (Sandbox Code Playgroud)

给出:

{sasenc}ACFD24061BF77D7D5362EE7C2D00D08B
Run Code Online (Sandbox Code Playgroud)

如果我将我的纯文本密码替换为代码中的编码值,则ODBC passthrough语句可以正常运行。

proc sql noprint;
  connect to odbc as remote (datasrc=cmg_report user=myuser password='{sasenc}68B279564BD2695538CDCDB301E8A357563480B0');
  create table sqlo as 
  select *
  from connection to remote
  (
  select top 1 * from application
  )
  ;
  disconnect from remote;
quit;
Run Code Online (Sandbox Code Playgroud)

并且日志正确掩盖了带有XXXXXXX的值。

961  proc sql noprint;
962    connect to odbc as remote (datasrc=cmg_report user=&user_cmg password=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX);
963    create table sqlo as
964    select *
965    from connection to remote
966    (
967    select top 1 * from application
968    )
969    ;
971  quit;
NOTE: Table WORK.SQLO created, with 1 rows and 29 columns.
NOTE: PROCEDURE SQL used (Total process time):
      real time           0.34 seconds
      cpu time            0.01 seconds
Run Code Online (Sandbox Code Playgroud)

上述方法的问题在于,如果某人可以访问代码,则可以使用加密密码登录,而无需知道纯文本密码。因此,尽管它隐藏了实际的密码,但它不提供安全性。对我来说似乎很傻,还是我错过了什么?编辑:如果您的ODBC密码恰好在其他地方使用,则可以提供一些安全性,尽管如此。

尝试2-使用SYMGET在此处链接至白皮书

问题在于,我根本无法获得所描述的在SAS中工作的技术。我在XP上运行SAS 9.2,试图连接到SQL Server数据库。

%let my_password = password;

proc sql noprint;
  connect to odbc (dsn=cmg_report uid=myuser pwd=symget('my_password'));
  create table sqlo as 
  select *
  from connection to remote
  (
  select top 1 * from application
  )
  ;
quit;
Run Code Online (Sandbox Code Playgroud)

我收到以下消息,提示登录失败:

1034      proc sql noprint;
1035        connect to odbc (dsn=cmg_report uid=myuser pwd=XXXXXX('my_password'));

ERROR: CLI error trying to establish connection: [Microsoft][SQL Server Native Client 10.0][SQL
Server]Login failed for user 'myuser'.
Run Code Online (Sandbox Code Playgroud)

看起来它正在尝试使用“ symget”作为实际密码(因为它已在日志中被屏蔽)。对此白皮书有一些回应,说将symget包装在%sysfunc调用中,但是symget()函数是SAS在%sysfunc调用中不允许的少数函数之一,因此我不知道怎么可能。

任何其他提示/建议/想法将不胜感激。

谢谢

编辑: 如果有一种技术可以options symbolgen macrogen打开电源,那就特别好了。

RWi*_*ill 4

Rob,我们遇到了类似的问题,并提出了一种不同的方法,允许我们所有的团队成员运行相同的程序,而无需将我们的 ID/密码存储在程序中。它要求每个团队成员都有一个 SAS 可以访问的安全存储的文本文件(除所有者之外没有任何权限)。

以下是 ID/PW 文件内容的示例:

machine odbc login XX_odbc_id_XX password XXodbc_pw_XX
machine oracle login XX_oracle_id_XX password XX_oracle_pw_XX
Run Code Online (Sandbox Code Playgroud)

我们在 UNIX 服务器上运行,因此我们将各个 id/pw 文件锁定在我们的主目录中,这样其他人就无法访问它,在本例中它被命名为“.netrc”。该线程末尾的宏应该存储在某个地方,那么程序将如下所示:

%let id_pw_text_file = ~/.netrc;

%ODBC_Acct;

proc sql;
   %ODBC_Connect
   create table sqlo as
      select * from connection to odbc
      (
          /*  [ Insert ODBC query here ]  */ 
      );
   %ODBC_Disconnect
   quit;
run;
Run Code Online (Sandbox Code Playgroud)

我尝试修改宏以在您的环境中工作,并删除大量特定于我们系统的代码,但显然我无法对其进行测试以确保其有效。如果您遇到问题,请告诉我,我会尽力帮助解决。希望这可以帮助。

/*********************************************************************
*  Name:  ODBC_Acct                                                  *
*  Desc:  Set global macro vars containing a users ODBC username     *
*         and password. Retrieves this information from a users      *
*         specific ID/PW file.                                       *
*********************************************************************/
%macro ODBC_Acct( mprint );
   %local __mprint __symbolgen __mlogic;
   %if ( %length( &mprint ) = 0 ) %then %let mprint = NO;
   %if ( %upcase( &mprint ) = NO ) %then %do;
      %let __mprint = %sysfunc( getoption( mprint ));
      %let __symbolgen = %sysfunc( getoption( symbolgen ));
      %let __mlogic = %sysfunc( getoption( mlogic ));
      options nomprint nosymbolgen nomlogic;
   %end;
   %global  odbc_user  odbc_pw;
   %Get_ID_PW( &id_pw_text_file , odbc , odbc_user , odbc_pw )
   %if ( %upcase(&__mprint) ne NOMPRINT ) %then %do;
      options &__mprint &__symbolgen &__mlogic;
   %end;
%mend;

/*********************************************************************
*  Name:  ODBC_Connect, ODBC_Disconnect                              *
*  Desc:  Returns SAS/Access connect or disconnect statements        *
*         for accessing ODBC.                                        *
*********************************************************************/
%macro ODBC_Connect( mprint=no );
   %local __mprint __symbolgen;
   %if ( %upcase(&mprint) = NO ) %then %do;
      %let __mprint = %sysfunc( getoption( mprint ));
      %let __symbolgen = %sysfunc( getoption( symbolgen ));
      options nomprint nosymbolgen;
   %end;
   connect to odbc as remote (
      datasrc=cmg_report
          user = "&odbc_user"
      password = "&odbc_pw"
      );
   %if ( %upcase(&__mprint) ne NOMPRINT ) %then %do;
      options &__mprint &__symbolgen;
   %end;
%mend;
%macro ODBC_Disconnect;
   disconnect from odbc;
%mend;

/*******************************************************************************
*  Name:  GetID_PW                                                             *
*  Desc:  Get loginid and password from a secured file                         *
*------------------------------------------------------------------------------*
*  Arguments:                                                                  *
*    1st   Required. Source file containing IDs and passwords.                 *
*    2nd   Required. Host id.                                                  *
*    3rd   Required. Specify the macro variable to put the loginid.            *
*    4th   Required. Specify the macro variable to put the password.           *
*------------------------------------------------------------------------------*
*******************************************************************************/
%macro Get_ID_PW( source , rhost , usrvar , pw_var );
   %let source_file = &source
   %if ( %sysfunc( fileexist( &source_file ) ) ) %then %do;
      %let rc  = %sysfunc( filename( dummy , &source_file ) );
      %let fid = %sysfunc( fopen( &dummy ) );
      %do %while( %sysfunc( fread( &fid ) ) = 0 );
         %let rc = %sysfunc( fget( &fid , inrec , 500 ) );
         %let machine = %scan( &inrec , 2 , %str( ) );
         %if ( %upcase( &machine ) = %upcase( &rhost ) ) %then %do;
            %let &usrvar = %scan( &inrec , 4 , %str( ) );
            %let &pw_var = %scan( &inrec , 6 , %str( ) );
            %goto Break;
         %end;
      %end;
      %Break: %*;
      %let rc = %sysfunc( fclose( &fid ) );
      %let rc = %sysfunc( filename( dummy ) );
   %end;
   %else %do;
       %put ::: ID/PW file "&source_file" not found;
   %end;
%mend;
Run Code Online (Sandbox Code Playgroud)