Oracle函数中的加密/解密密码

时间:2012-08-21 15:33:20

标签: oracle encryption plsql

由于之前设计不合理的结构,我必须使用的当前数据库将用户的密码存储为文本。

现在,我正在构建一个必须使用这些密码的前端部分,我当然不希望发送未加密的密码。

我的想法是编写一个Oracle函数来加密和解密文本密码,并在存储过程中使用这些函数来返回加密数据。

Oracle最好的方法是什么?

5 个答案:

答案 0 :(得分:7)

如果您想编写自己的函数来加密和解密数据,您只需要使用适当的参数调用DBMS_CRYPTO encryptdecrypt方法(即选择加密算法) ,你的钥匙等。)。

当然,如果您编写自己的例程,假设您将密钥存储在数据库中或数据库可以访问的某个位置,那么您的安全性并不高。通过网络发送未加密的密码是不好的,但在数据库中存储未加密的密码通常要糟糕得多(如果数据库中有decrypt方法可以访问密钥来解​​密数据,则加密密码) 。从数据库窃取数据通常比通过网络发送数据以查找密码容易得多。

当然,正确的答案是重新架构系统,以便您根本不存储密码。您应该存储不可逆的密码哈希值(您也可以使用DBMS_CRYPTO包生成)。

答案 1 :(得分:6)

看看DBMS_CRYPTO

它有加密和解密内置数据的方法。比编写自己的方法更好。

http://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_crypto.htm

答案 2 :(得分:4)

这是使用(DBMS_CRYPTO)加密密码的打包功能(成功实施) -

CREATE OR REPLACE
PACKAGE BODY encrypt_paswd
AS
  G_CHARACTER_SET VARCHAR2(10) := 'AL32UTF8';
  G_STRING VARCHAR2(32) := '12345678901234567890123456789012';
  G_KEY RAW(250) := utl_i18n.string_to_raw
                      ( data => G_STRING,
                        dst_charset => G_CHARACTER_SET );
  G_ENCRYPTION_TYPE PLS_INTEGER := dbms_crypto.encrypt_aes256 
                                    + dbms_crypto.chain_cbc 
                                    + dbms_crypto.pad_pkcs5;
  ------------------------------------------------------------------------
  --Encrypt a password 
  --Salt the password
  ------------------------------------------------------------------------
  FUNCTION encrypt_val( p_val IN VARCHAR2 ) RETURN RAW
  IS
    l_val RAW(32) := UTL_I18N.STRING_TO_RAW( p_val, G_CHARACTER_SET );
    l_encrypted RAW(32);
  BEGIN
    l_val := utl_i18n.string_to_raw
              ( data => p_val,
                dst_charset => G_CHARACTER_SET );

    l_encrypted := dbms_crypto.encrypt
                   ( src => l_val,
                     typ => G_ENCRYPTION_TYPE,
                     key => G_KEY );

    RETURN l_encrypted;
  END encrypt_val;
END encrypt_paswd;

这使用encrypt_aes256 - “高级加密标准。分组密码。使用256位密钥大小。” ,chain_cbc - “密码块链接。明文在加密之前与之前的密文块进行异或。”和pad_pkcs5 - “提供符合PKCS#5:基于密码的加密标准的填充”。

除此之外您还可以创建类似的解密功能。喜欢 -

  FUNCTION decrypt_val( p_val IN RAW ) RETURN VARCHAR2  
  IS
    l_decrypted RAW(32);
    l_decrypted_string VARCHAR2(32);
    l_user  VARCHAR2(32);
  BEGIN
    SELECT user 
      INTO l_user
      FROM dual;

    if l_user = 'ADMIN' -- you can restrict usage of decrypt to certain db users only.
    then
        l_decrypted := dbms_crypto.decrypt
                ( src => p_val,
                  typ => G_ENCRYPTION_TYPE,
                  key => G_KEY );

        l_decrypted_string := utl_i18n.raw_to_char
                    ( data => l_decrypted,
                      src_charset => G_CHARACTER_SET );
        RETURN l_decrypted_string;
    else            
            RAISE_APPLICATION_ERROR(-20101, 'You are not authorized to use this function - decrypt_val()');
    end if;
    RETURN 'Unknown';
  END decrypt_val;

您可以考虑使用wrap iname=package_name.pkb在数据库中编译包之前包装该包,然后编译生成的plb

答案 3 :(得分:4)

或者你可以像这样http://mikepargeter.wordpress.com/2012/11/26/pbkdf2-in-oracle/使用密码哈希算法pbkdf2 我使用rfc https://www.ietf.org/rfc/rfc6070.txt验证了结果,它运行正常。

检查此链接以获得最少的迭代次数和key_size:PBKDF2 recommended key size? 请注意,结果是长度的两倍,因为它是十六进制编码的。

我们将这些列存储在db

PASSWORD_HASH                 VARCHAR2(512 BYTE),
PASSWORD_SALT                 VARCHAR2(256 BYTE),
PASSWORD_ITERATIONS           NUMBER(10),
PASSWORD_HASH_METHOD          VARCHAR2(30 BYTE),
PASSWORD_CHANGED_DT           DATE

散列,盐和迭代是为pbkdf2算法提供的 hash_method用于迁移目的 而changed_dt将使密码失效

答案 4 :(得分:0)

用户此代码肯定有效

DELIMITER $$

DROP PROCEDURE IF EXISTS `thread_updates` $$
CREATE PROCEDURE `thread_updates`()
BEGIN

DECLARE my_total INT DEFAULT NULL; -- Declare total
DECLARE my_counter INT DEFAULT 0; -- Declare counter starting at 0
DECLARE my_curr_id INT DEFAULT NULL;
-- DECLARE other vars
DECLARE fixer_cursor CURSOR FOR
  SELECT DISTINCT(id)
  FROM log
  WHERE date >= '2018-01-01';

OPEN fixer_cursor;

SELECT FOUND_ROWS() INTO my_total; -- Get total number of rows

my_fixerloop: LOOP

  FETCH fixer_cursor INTO my_curr_id;
  IF my_counter >= my_total THEN -- Compare counter to total
    CLOSE fixer_cursor;
    LEAVE my_fixerloop;
  END IF;

  SET my_counter = my_counter + 1; -- Increment by one for each record

  SELECT data FROM table WHERE id = my_curr_id; -- This may not exist 
  -- Do other stuff with 'data' or NULL from above

END LOOP;
END $$
DELIMITER ;