В данном примере мы будем использовать пакет DBMS_OBFUSCATION_TOOLKIT, который доступен, начиная с Oracle8i:
Таблицы с секретными данными
Для начала мы должны создать таблицы для хранения секретной информации.
CREATE TABLE app_users ( id NUMBER(10) NOT NULL, username VARCHAR2(30) NOT NULL, password VARCHAR2(16) NOT NULL ) / ALTER TABLE app_users ADD ( CONSTRAINT app_users_pk PRIMARY KEY (id) ) / ALTER TABLE app_users ADD ( CONSTRAINT app_users_uk UNIQUE (username) ) / CREATE SEQUENCE app_users_seq /
Пакет для работы с шифрованием
Cоздадим спецификацию пакета шифрования:
CREATE OR REPLACE PACKAGE app_user_security AS
FUNCTION get_hash (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN VARCHAR2;
PROCEDURE add_user (p_username IN VARCHAR2,
p_password IN VARCHAR2);
PROCEDURE change_password (p_username IN VARCHAR2,
p_old_password IN VARCHAR2,
p_new_password IN VARCHAR2);
PROCEDURE valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2);
FUNCTION valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN BOOLEAN;
END;
/
Затем создадим тело, определив актуальные операции:CREATE OR REPLACE PACKAGE BODY app_user_security AS
FUNCTION get_hash (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN VARCHAR2 AS
BEGIN
RETURN DBMS_OBFUSCATION_TOOLKIT.MD5(
input_string => UPPER(p_username) || '/' || UPPER(p_password));
END;
PROCEDURE add_user (p_username IN VARCHAR2,
p_password IN VARCHAR2) AS
BEGIN
INSERT INTO app_users (
id,
username,
password
)
VALUES (
app_users_seq.NEXTVAL,
UPPER(p_username),
get_hash(p_username, p_password)
);
COMMIT;
END;
PROCEDURE change_password (p_username IN VARCHAR2,
p_old_password IN VARCHAR2,
p_new_password IN VARCHAR2) AS
v_rowid ROWID;
BEGIN
SELECT rowid
INTO v_rowid
FROM app_users
WHERE username = UPPER(p_username)
AND password = get_hash(p_username, p_old_password)
FOR UPDATE;
UPDATE app_users
SET password = get_hash(p_username, p_new_password)
WHERE rowid = v_rowid;
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000, 'Invalid username/password.');
END;
PROCEDURE valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2) AS
v_dummy VARCHAR2(1);
BEGIN
SELECT '1'
INTO v_dummy
FROM app_users
WHERE username = UPPER(p_username)
AND password = get_hash(p_username, p_password);
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000, 'Invalid username/password.');
END;
FUNCTION valid_user (p_username IN VARCHAR2,
p_password IN VARCHAR2)
RETURN BOOLEAN AS
BEGIN
valid_user(p_username, p_password);
RETURN TRUE;
EXCEPTION
WHEN OTHERS THEN
RETURN FALSE;
END;
END;
/
Перегрузка VALID_USER позволяет проверить правильность пары логин/пароль разными способами.Функция GET_HASH используется для получения хэша для пары логин/пароль. Она всегда возвращает результат равный VARCHAR2(16) вне зависимости от входных данных. Этот уровень сжатия означает, что хэш-значение не может быть уникальным, поэтому требуется ограничение уникальности по стобцу с именем пользователя.
Функция DBMS_UTILITY.GET_HASH_VALUE может быть использована вместо функции DBMS_OFUSCATION_TOOLKIT.MD5, но алгоритм хэширования у первой может отличаться в разных версиях БД.
Тестирование
Сначала мы создадим нового пользователя:
SQL> exec app_user_security.add_user('tim','hall');
PL/SQL procedure successfully completed.
SQL> select * from app_users;
ID USERNAME PASSWORD
---------- ------------------------------ ----------------
1 TIM [w?44Z??8fE??
Проверим процедуру VALID_USER:SQL> EXEC app_user_security.valid_user('tim','hall');
PL/SQL procedure successfully completed.
SQL> EXEC app_user_security.valid_user('tim','abcd');
BEGIN app_user_security.valid_user('tim','hall1'); END;
*
ERROR at line 1:
ORA-20000: Invalid username/password.
ORA-06512: at "W2K1.APP_USER_SECURITY", line 37
ORA-06512: at line 1
Проверим функцию VALID_USER:SQL> SET SERVEROUTPUT ON
SQL> BEGIN
2 IF app_user_security.valid_user('tim','hall') TH
3 DBMS_OUTPUT.PUT_LINE('TRUE');
4 ELSE
5 DBMS_OUTPUT.PUT_LINE('FALSE');
6 END IF;
7 END;
8 /
TRUE
PL/SQL procedure successfully completed.
SQL> BEGIN
2 IF app_user_security.valid_user('tim','abcd') T
3 DBMS_OUTPUT.PUT_LINE('TRUE');
4 ELSE
5 DBMS_OUTPUT.PUT_LINE('FALSE');
6 END IF;
7 END;
8 /
FALSE
PL/SQL procedure successfully completed.
SQL>
В заключении мы проверим процедуру CHANGE_PASSWORD:SQL> exec app_user_security.change_password('tim','hall','hall1');
PL/SQL procedure successfully completed.
SQL> exec app_user_security.change_password('tim','abcd','abcd1');
BEGIN app_user_security.change_password('tim','abcd','abcd1'); END;
*
ERROR at line 1:
ORA-20000: Invalid username/password.
ORA-06512: at "W2K1.APP_USER_SECURITY", line 47
ORA-06512: at line 1
SQL>
Отсюда.
Комментариев нет:
Отправить комментарий