목차
1. Oracle Hash
1-1 Oracle Hash 개요
1-2 Oracle Hash 종류 상세
2. 오라클 Client 설치
3. PHP - 세션
3-1 세션 개요
3-2 세션을 이용한 인증 처리
1. Oracle Hash
1-1 Oracle Hash 개요
● Oracle Hash 종류
| STANDARD_HASH | - VARCHAR2 타입의 데이터 처리가 가능하다. - 다양한 알고리즘 선택이 가능하다. - 패스워드 등 다양한 보안상의 요구를 위해 제공된다. |
| DBMS_CRYPTO.HASH | - 여러 보안상의 요구를 위해 제공된다. - RAW 타입 데이터를 생성한다. - 다양한 알고리즘 선택이 가능하다. - RAW 타입의 데이터만 처리가 가능하다. |
| ORA_HASH | - 오라클 고유 알고리즘을 이용한다. - 성능이 빠르다. - 보안을 위해서 사용하는 것은 아니다. |
- STANDARD_HASH
: 원래 존재하는 표준 함수로, 특별한 권한 없이도 사용이 가능하다.
: 텍스트 타입의 데이터를 바로 전달해 줄 수 있다.
- DBMS_CRYPTO.HASH
: DBMS_CRYPTO는 패키지 이름이다.
: 다양한 형태의 함수를 제공하며 해시 코드를 만들 때 내부적으로 효율적이다.
- ORA_HASH
: 오라클 고유 알고리즘이다. 즉, 무슨 알고리즘인지 알 수 없다.
: 데이터의 빠른 저장/찾기를 위해 사용한다.
● RAW와 문자열
| 문자열 (VARCHAR2, CHAR) | RAW (RAW, LONG RAW) | |
| 정의 | 문자열 | 바이너리 데이터 (byte) |
| 저장 | UTF8과 같은 문자셋으로 인코딩된 문자열 | 바이너리 데이터 |
| 용도 | 텍스트 저장이나 출력 | 바이너리 데이터 처리 |
| 인식 | 'A' : 문자 A로 인식 | 0x41은 그냥 0x41로 인식 |
| 비교 | 문자셋 기반의 문자 단위 인식 | byte 단위 인식 |
| 용도 | 텍스트 데이터 처리 | 해시, 암호와 같은 바이너리 처리 |
| 비교 | 비교 연산 가능 | RAW 간에만 가능 |
- 바이너리 데이터는 직접 일을 수 없다.
- 해시, 암호는 모두 바이너리 처리가 되어있다.
1-2 Oracle Hash 종류 상세
● STANDARD_HASH
다음과 같은 다양한 알고리즘을 지원한다.
- 'MD5', 'SHA1', 'SHA256', 'SHA384', 'SHA512'
해시 결과는 RAW 타입으로 저장된다.
- 저장: RAW 타입으로 저장할 수 있으나 뭔가 처리할 때 헥사코드로 처리하므로 주로 RAWTOHEX()를 이용해 HEX 문자열로 저장한다.
- 출력 결과는 RAW,HEX 문자열이 동일해 보이나 내부 처리는 다르다.
※ 알고리즘에 따른 결과
| bit 길이 | RAW 길이 | HEX 길이 | |
| MD5 | 128 | 16 | 32 |
| SHA1 | 160 | 20 | 40 |
| SHA256 | 256 | 32 | 64 |
| SHA384 | 384 | 48 | 96 |
| SHA512 | 512 | 64 | 128 |
※ 각 알고리즘 별 컬럼 타입
| RAW 타입 | VARCHAR2 타입 | ||
| MD5 | RAW (16) | VARCHAR2 (32) | |
| SHA1 | RAW (20) | VARCHAR2 (40) | |
| SHA256 | RAW (32) | VARCHAR2 (64) | |
| SHA384 | RAW (48) | VARCHAR2 (96) | |
| SHA512 | RAW (64) | VARCHAR2 (128) | |
- RAWTOHEX()를 사용하는 경우 VARCHAR2() 타입에 저장하고 이를 사용하지 않는 경우에는 RAW() 타입의 컬럼을 사용한다.
- 해시 결과를 출력하거나 비교하는 일이 있다면 VARCHAR2를 권장한다. VARCHAR2는 큰 공간을 할당시켜줘도 필요한 만큼만 메모리를 차지하므로 그냥 VARCHAR2 (128)을 사용하면 된다.
● STANDARD_HASH 실습
STANDARD_HASH('문자열','알고리즘') : RAW 타입
RAWTOHEX(STANDARD_HASH('문자열','알고리즘')) : HEX 문자열
다음과 같이 작성하여 STANDARD_HASH('asdf', 'SHA256')와 RAWTOHEX(STANDARD_HASH('asdf', 'SHA256'))의 출력값은 완전히 같은 것을 알 수 있다.
SQL> SELECT STANDARD_HASH('asdf', 'SHA256'),
2 RAWTOHEX(STANDARD_HASH('asdf', 'SHA256'))
3 FROM dual
4 WHERE STANDARD_HASH('asdf', 'SHA256') =
5 RAWTOHEX(STANDARD_HASH('asdf', 'SHA256'));
- STANDARD_HASH는 RAW 타입으로 저장되나, RAW 타입 데이터는 사람이 직접 읽을 수 없는 데이터이므로 자동으로 헥사 코드로 출력되어 RAWTOHEX를 이용한 것과 값이 같다.
- =, LIKE, IN 연산자의 경우 RAW에서 VARCHAR2로 자동 형 변환을 제공한다. 그러나 자동 형 변환을 사용하면 속도 저하와 신뢰도 문제가 있으므로 RAWTOHEX를 이용한 수동 형 변환을 권장한다.
다음과 같이 테이블을 설계하는 경우도 RAW보다 VARCHAR2를 권장한다.
SQL> CREATE TABLE ID(
2 RAW_DATA RAW(64),
3 HEX_DATA VARCHAR2(128)
4 );
● DBMS_CRYPTO.HASH
기본 제공되는 함수가 아니므로 DBMS_CRYPTO 패키지에 대한 실행 권한이 필요하다.
SQL> GRANT EXECUTE ON DBMS_CRYPTO TO 대상;
매개 인자와 리턴 값은 모두 RAW 타입이다.
- 문자열을 RAW로 변환해서 사용한다.
(UTL_I18N.STRING_TO_RAW를 이용한다.)
- 인코딩은 'AL32UTF8'로 지정한다. (권장사항)
SQL> UTL_I18N.STRING_TO_RAW('입력문자열', 'AL32UTF8')
※ 오라클 권장 방식
SQL> DBMS_CRYPTO함수(UTL_I18N.STRING_TO_RAW('문자열', 'AL32UTF8'), 해시알고리즘);
※ DBMS_CRYPTO의 함수
| ENCRYPT | 데이터를 암호화한다. (암호화 알고리즘, 키, 패딩, 모드 설정 필요) |
| DECRYPT | 데이터를 복호화한다. |
| HASH | 문자열이나 RAW 데이터를 해시 처리한다. (MD5, SHA‐1, SHA‐2 등) |
| RANDOMBYTES | 지정된 길이의 랜덤 바이트를 생성한다. (난수 생성) |
| . . . | . . . |
- DBMS_CRYPTO 는 암호화 알고리즘이나 해시 알고리즘 등 함수 옵션을 상수로 표현한다.
| 1 | MD5 해시 |
| 2 | SHA‐1 해시 |
| 4 | SHA‐256 해시 |
| 5 | SHA‐384 해시 |
| 6 | SHA‐512 해시 |
| 1 | AES 128비트 암호화 |
| 2 | AES 192비트 암호화 |
| 3 | AES 256비트 암호화 |
| 4 | 3DES 암호화 |
| 5 | DES 암호화 |
| 6 | RC4 암호화 |
해시값 저장은 STANDARD_HASH와 동일하다.
ex) SHA‐256 알고리즘으로 해시코드를 출력한다.
SQL> SELECT RAWTOHEX(
DBMS_CRYPTO.HASH(
UTL_I18N.STRING_TO_RAW('hello', 'AL32UTF8'), 4
)
)
2 FROM dual;
2. 오라클 Client 설치
다음과 같이 리눅스 서버에 오라클 클라이언트를 설치하여 오라클을 이용할 수 있다.
① 패키지 다운과 설치
// 패키지 다운로드
# dnf install ‐y wget
# wget https://download.oracle.com/otn_software/linux/instantclient/1925000/oracle‐instantclient19.25‐basic‐19.25.0.0.0‐1.x86_64.rpm
# wget https://download.oracle.com/otn_software/linux/instantclient/1925000/oracle‐instantclient19.25‐devel‐19.25.0.0.0‐1.x86_64.rpm
# wget https://download.oracle.com/otn_software/linux/instantclient/1925000/oracle‐instantclient19.25‐sqlplus‐19.25.0.0.0‐1.x86_64.rpm
// 패키지 설치
# dnf install ‐y oracle‐instantclient19.25‐basic‐19.25.0.0.0‐1.x86_64.rpm
# dnf install ‐y oracle‐instantclient19.25‐devel‐19.25.0.0.0‐1.x86_64.rpm
# dnf install ‐y oracle‐instantclient19.25‐sqlplus‐19.25.0.0.0‐1.x86_64.rpm
② sqlnet.ora 파일과 tnsnames.ora 파일 생성
# mkdir ‐p /usr/lib/oracle/network/admin/
# echo 'NAMES.DIRECTORY_PATH= (TNSNAMES)' > /usr/lib/oracle/network/admin/sqlnet.ora
# cat <<EOF > /usr/lib/oracle/network/admin/tnsnames.ora
oracle = (DESCRIPTION =
(ADDRESS = (PROTOCOL = tcp) (HOST = 서버_IP) (port = 1521))
(CONNECT_DATA = (SID = DB19))
)
EOF
③ 접속 환경 설정
# echo 'export TNS_ADMIN=/usr/lib/oracle/network/admin' >> /etc/profile
# echo 'export LD_LIBRARY_PATH=/usr/lib/oracle/19.25/client64/lib' >> /etc/profile
# echo 'export NLS_LANG=AMERICAN_AMERICA.AL32UTF8' >> /etc/profile
④ 접속 테스트
sqlplus 계정/패스워드@oracle
3. PHP - 세션
3-1 세션 개요
세션은 한 페이지에서 변수에 저장한 값을 여러 페이지를 방문하는 동안 계속 유지하는 방법으로, 네이버에 로그인 한 상태를 유지하며 내 계정의 블로그나 카페를 방문할 때 세션이 쓰인다.
세션을 이용하여 다음 a.php의 변수값을 b.php에서도 저장하여 이용할 수 있다.
※ a.php
<?
session_start();
$_SESSION["name"] = '홍길동';
$_SESSION["passwd"] = '암호';
$name=$_SESSION["name"];
$passwd= $_SESSION["passwd"];
echo(" name = $name <br>");
echo(" passwd = $passwd <br>");
echo("<a href='./b.php'>b.php</a>");
?>
※ b.php
<?
session_start();
$name = $_SESSION["name"];
$passwd = $_SESSION["passwd"];
echo(" name = $name <br>");
echo(" passwd = $passwd <br>");
session_destroy();
?>
session_start() 를 이용해 세션을 시작한다. 세션은 하드드라이브에 만들어지며, 항상 파일의 첫 머리에 나와야 한다.
a.php의 $_SESSION["name"] 변수와 $_SESSION["passwd"] 변수에 세션 값을 저장하여 b.php의 변수에 동일한 세션 값을 저장할 수 있다.
이 세션 값들은 session _destroy() 함수나 session_unset() 함수를 호출하여 세션을 종료하기 전까지 계속 유지된다.
● 세션 관련 함수
| session_start () | - 세션을 시작한다. - 매개 변수 없이 쓰인다. - session.auto_start=1로 설정하면 함수를 자동으로 실행한 것과 동일하다. - $_SESSION 배열을 이용해서 세션 변수를 등록한다. |
| session_destroy() | - 세션을 종료한다. - 매개 변수 없이 쓰인다. - 이후 세션을 이용하려면 새로운 세션을 시작해야 한다. |
3-2 세션을 이용한 인증 처리
다음과 같이 id.html, id.php를 이용해 계정을 등록하고 check.html, check.php를 이용해 로그인하는 프로그램을 작성할 수 있다.
● 인증을 위한 테이블 추가 - 오라클에서 테이블 생성
CREATE TABLE id(
id VARCHAR2(50),
passwd VARCHAR2(128),
CONSTRAINT id_pk_id PRIMARY KEY (id)
);
● 계정 등록 프로그램
// id.html //
<html><head>
<meta http-equiv="content-type" content="text/html; charset=euc-kr">
<title> 계정등록 </title>
</head>
<body bgcolor="white" text="black" link="blue" vlink="purple" alink="red">
회원가입
<form name="id" action="id.php" method="POST">
<center>
<table border="0" width="250">
<tr>
<td width="50"><p align="center">ID</p></td>
<td> <input type="text" name="id"></td>
</tr>
<tr>
<td width="50"><p align="center">passwd</p></td>
<td> <input type="password" name="passwd"></td>
</tr>
<tr>
<td colspan="2">
<p align="center"><input type="submit" name="확인" value="확인"></p>
</td>
</tr>
</table>
</center>
</form>
<br><hr><br>
<? show_source(__FILE__); ?>
</body></html>
// id.php //
<html>
<head>
<title>id.php</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
<?
require('conn.php');
$id = $_POST["id"];
$passwd = $_POST["passwd"];
$sql="insert into id (id, passwd)
values ('$id', RAWTOHEX(STANDARD_HASH('$passwd', 'SHA256')))";
$result=oci_parse($conn,$sql);
$re=@oci_execute($result); // 입력된 값을 테이블에 저장한다.
oci_free_statement($result);
oci_close($conn);
if(!$re)
{ echo(" <script>
window.alert('계정 등록 장애입니다.');
history.go(-1);
</script>
");
exit;
} // st_vi.php를 호출할 때 $id나 $passwd는 세션변수에
else // 등록되었으므로 전달할 필요가 없다.
echo(" <meta http-equiv='Refresh' content = '0; URL=check.html'>");
?>
</form>
<br><hr><br>
<? show_source(__FILE__); ?>
</body>
</html>
● 로그인 프로그램
// check.php //
<html><head>
<meta http-equiv="content-type" content="text/html; charset=euc-kr">
<title> login </title>
</head>
<body bgcolor="white" text="black" link="blue" vlink="purple" alink="red">
로그인
<form name="login" action="check.php" method="POST">
<center>
<table border="0" width="250">
<tr>
<td width="50"><p align="center">ID</p></td>
<td> <input type="text" name="id"></td>
</tr>
<tr>
<td width="50"><p align="center">passwd</p></td>
<td> <input type="password" name="passwd"></td>
</tr>
<tr>
<td colspan="2">
<p align="center"><input type="submit" name="확인" value="확인"></p>
</td>
</tr>
</table>
</center>
</form>
<br><hr><br>
<? show_source(__FILE__); ?>
</body></html>
// check.php //
<html>
<head>
<title>check.php</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
<?
session_start();
require('conn.php');
$id = $_POST["id"];
$passwd = $_POST["passwd"];
$sql="select * from id
where id = '$id'
and passwd = RAWTOHEX(STANDARD_HASH('$passwd', 'SHA256'))";
$result=oci_parse($conn,$sql);
$re=oci_execute($result);
$row_num=oci_fetch_all($result,$row);
oci_free_statement($result);
oci_close($conn);
if($row_num == 1){
$_SESSION["id"] = $id;
$_SESSION["passwd"] = $passwd;
echo(" <meta http-equiv='Refresh' content = '0; URL=st_vi.php'>");
}
else{
echo(" <script>
window.alert('잘못된 계정 정보입니다.');
history.go(-1);
</script>
");
exit;
}
?>
<br><hr><br>
<? show_source(__FILE__); ?>
</body>
</html>
● 로그인에 따른 화면 변화
앞서 작성한 check.html과 check.php에서는 등록한 아이디와 패스워드를 입력했을 때 st_vi.php를 호출하도록 로그인 프로그램을 작성하였으나 로그인이라는 것은 로그인 전과 후의 화면이 차이가 있어야 의미가 있다.
다음과 같이 로그인 여부에 따라 출력 화면을 달리 하여 로그인이 의미를 갖도록 st_vi.php를 개선할 수 있다.
// st_vi.php 로그인 여부에 따른 화면 출력 개선 //
<html>
<head>
<title>st_vi.php</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
</head>
<body>
<?
session_start();
if(empty($_GET["logout"])){}
else session_unset(); // session_distroy 사용과 비교한다.
require('conn.php');
$id = $_SESSION["id"];
$passwd = $_SESSION["passwd"];
$sql="select * from id
where id = '$id'
and passwd = RAWTOHEX(STANDARD_HASH('$passwd', 'SHA256'))";
$result=oci_parse($conn,$sql);
$re=oci_execute($result);
$row_num=oci_fetch_all($result,$row);
if($row_num == 1){ // 로그인 상태
echo("<a href=./st_in.html>자료 입력하기</a>
<a href=./st_vi.php?logout=$row_num>logout</a><hr>
");
}
else{ // 비로그인 상태
echo(" <a href=./id.html>계정등록</a>
<a href=./check.html>login</a><hr>");
}
?>
<?
echo("<a href=./st_in.html>자료 입력하기</a><hr>");
require('conn.php');
// =========================== 삭제
$del=$_GET['del'];
if (empty($del)){}
else {
$sql="delete from student where sno='$del'";
$result=oci_parse($conn,$sql);
oci_execute($result);
oci_free_statement($result);
}
// ===========================
// =========================== 검색
$search = $_GET['search'];
if (empty($search))
{
$sql="select sno,sname,sex,major,syear,to_char(avr,'0.00') avr
from student order by sno";
}
else
{
$sql="select sno,sname,sex,major,syear,to_char(avr,'0.00') avr
from student
where sname like '%{$search}%' order by sno";
}
// ===========================
$result=oci_parse($conn,$sql);
oci_execute($result);
$row_num=oci_fetch_all($result, $row); // $row_num : 전제 행의 수
oci_free_statement($result);
oci_close($conn);
echo("Row의 개수는 $row_num 입니다.<br><hr>");
$scale=5; // 화면에 출력할 행의 개수
$start = $_GET['start'];
if (empty($start)){ $start=0;} // 첫 화면은 0에서 시작, 배열의 키값은 0에서 시작
echo("<table border='0'>");
for ($i=$start; $i<($start+$scale); $i++) {
if($i<$row_num){
echo("
<tr>
<td width='50'><p align='center'>{$row['SNO'][$i]}</p></td>
<td width='80'><p align='center'>{$row['SNAME'][$i]}</p></td>
<td width='20'><p align='center'>{$row['SEX'][$i]}</p></td>
<td width='20'><p align='center'>{$row['SYEAR'][$i]}</p></td>
<td width='50'><p align='center'>{$row['MAJOR'][$i]}</p></td>
<td width='30'><p align='center'>{$row['AVR'][$i]}</p></td>
<td width='30'><a href=./st_vi.php?del={$row['SNO'][$i]}>del</a></td>
</tr>
");
}
}
echo("</table><hr>");
$p=$start-$scale; // 이전 화면의 시작 위치
$n=$start+$scale; // 다음 화면의 시작 위치
if($p>=0)
echo("<a href=./st_vi.php?start=$p&search=$search>[이전페이지]</a> ");
else
echo("이전페이지 ");
if($n<$row_num)
echo("<a href=./st_vi.php?start=$n&search=$search>[다음페이지]</a>");
else
echo("다음페이지");
?>
<form name='search' method='get' action='st_vi.php'>
검색창 <input type='text' name='search'>
<input type='submit' name='확인' value='확인'>
</form>
<br><hr><br>
<? show_source(__FILE__); ?>
</body>
</html>
7 ~ 35행 프로그래밍 작성
: 기존 st_vi.php 파일에 7 ~ 35행 프로그래밍을 추가로 작성하여 로그인 여부에 따라 다른 버튼이 출력되도록 한다.
- 로그인 시: '자료입력', 'logout' 버튼 출력
- 비로그인 시: '계정등록', 'login' 버튼 출력
'일일 정리' 카테고리의 다른 글
| 오라클 클라이언트 - 아파치 - PHP 연동, php.ini 보안 설정 (1) | 2025.03.31 |
|---|---|
| PHP - SALT 값, 논리 모델링 구성 실습 (1) | 2025.03.28 |
| PHP - 오라클 DB 연동, 논리 모델링 구성 (0) | 2025.03.25 |
| PHP - 오라클 DB 연동, 논리 모델링 구성 (0) | 2025.03.24 |
| 정규화와 모델링, 논리 모델링 구성, PHP - 오라클 DB 연동 (2) | 2025.03.22 |