SSL용 DES 암호화 함수

문자열을 트리플-DES  알고리즘을 이용해 주어진 키로 암호화하는 함수입니다. 이 함수는 mysql SSL 사용이 설정되어 있는 경우에만 동작합니다. 첫번째 인자는 암호화할 문자열를, 두번째는 암호화 키로 선택됩니다. 그리고 key 는 숫자이거나 문자가 올 수 있으며, 에러가 발생하면, NULL를 반환합니다.

 # 암호화할 때 사용
 SELECT DES_ENCRYPT(str, key); 

 # 복호화할때 사용
 SELECT DES_DECRYPT(str, key);

예제(ex #1
 # 암호화
 mysql> SELECT DES_ENCRYPT('card_number', '123456789');

 # 복호화
 mysql> SELECT DES_DECRYPT(암호화 값, '123456789');
 
ENCRYPT 암호화 함수

유닉스 crypt() 시스템을 사용하는 encrypt 함수는 바이너리 문자열을 반환하고, salt 인자는 적어도 두글자를 갖는 문자열이어야 합니다. salt 인자가 주어지지 않으면, 랜덤값이 주어집니다.

 SELECT ENCRYPT(str, [,salt]);

예제(ex #2
 mysql> SELECT ENCRYPT('hello');
      > VxuFAJXVARR0c
 
ENCODE, DECODE 암호화 함수

encode 함수는 key 가 주어진 str를 암호화하며, 복호화는 decode를 사용합니다.

 # 암호화
 SELECT ENCODE(str, key);

 # 복호화
 SELECT DECODE(str, key);

예제(ex #3
 mysql> SELECT ENCODE('TEST', '123456789');
      > 험$i
블로그 이미지

하보니

하보니와 함께하는 phP 초보

Tag 암호화

댓글을 달아 주세요

이 함수는 일반 문자열을 str 를 암호화한 바이너리 문자열을 반환합니다. str 이 NULL 이면 NULL 를 반환합니다.

 SELECT PASSWORD(str);

예제(ex #1
 mysql> SELECT PASSWORD('test');
      -> *47A6B0EA08A36FAEBE4305B373FE37E3CF27C357

 관련글: 2011/09/30 - 브루트 포스 공격 (brute force attack)
            2011/09/30 - [mysql] MD5, SHA1 단방향 암호화 함수
            2011/09/14 - [mysql] 데이터의 암호화, 복호화하는 AES 함수
블로그 이미지

하보니

하보니와 함께하는 phP 초보

Tag 암호화

댓글을 달아 주세요

mysql 에 단방향 암호화함수가 있는데, md5, sha1 함수가 그 것입니다. 이 함수는 php 함수와 동일한 기능으로 작동하는데, md5 는 128비트 체크섬을 계산하여 32헥사 자리 바이너리 문자열을 반환하고, sha1 함수는 RFC 3174로 묘사된 문자에 대한 160 비트 체크섬을 계산하여 40 헥사 자리 바이너리 문자열을 반환합니다.

 SELECT MD5(str);
 SELECT SHA1(str);

예제(ex #1
 mysql> SELECT MD5('test');
      -> 098f6bcd4621d373cade4e832627b4f6

 mysql> SELECT SHA1('test');
      -> a94a8fe5ccb19ba61c4c0873d391e987982fbbd3

 // SHA 함수는 SHA1 함수의 동의어입니다.
 mysql> SELECT SHA('test');
      -> a94a8fe5ccb19ba61c4c0873d391e987982fbbd3

예제(ex #2
 mysql> SELECT SHA1(MD5('test'));
      -> 4028a0e356acc947fcd2bfbf00cef11e128d484a

관련글: 2011/09/30 - 브루트 포스 공격 (brute force attack)
           2011/09/30 - [mysql] PASSWORD 함수
           2011/09/14 - [mysql] 데이터의 암호화, 복호화하는 AES 함수
블로그 이미지

하보니

하보니와 함께하는 phP 초보

Tag 암호화

댓글을 달아 주세요

단방향 암호화란? 평문으로 암호화할 수 있어도 암호화된 암호문을 평문으로 복원할 수 없는 비가역적 암호화를 말합니다. 다시 말해 복원이 불가능한 상태입니다.

  평문 암호화  복호화  
 양방향 test 098f6bcd4621d373cade4e832627b4f6  test  가역적
 단방향 test 098f6bcd4621d373cade4e832627b4f6    비가역적

일반적으로 단방향 암호화는 실제 많이 사용하는 방법이며, 특히 php 유저는 md5 알고리즘을 널리 사용합니다. 이 방법은 암호화하고자 하는 문자열을 받아 128비트로 된 값을 만들어 낸다고 합니다.

문제는 md5 알고리즘도 보안의 허점에 노출되는 등 보안 강화가 필요한 현 시점에 진보된 해쉬 알고리즘이 필요합니다. 현재 문제시 되는 단순히 숫자로만 이루어져 있거나 영문, 숫자로 이루어져 있더라도 암호길이가 짧아 보안에 취약합니다.

짧은 암호는 해독에 걸리는 시간이 그리 길지 않습니다. 그 만큼 컴퓨터의 성능 또한 진보했으니까요.

진보된 알고리즘을 이용해 암호화하여 디비에 저장하되, 사용자가 로그인에 사용될 패스워드를 저장하는 것 만큼 중요하게 다뤄야 하는데, 숫자, 영문자를 포함하여 9자 이상 패스워드를 입력하게 하고, md5 에 임의의 값을 더한 값에 sha1 이나 sha512 와 같은 알고리즘으로 한번 더 암호화하여 저장하도록 합니다.

간단한 암호를 사용하는 것은 브루트 포스 공격(brute force attack)의 공격 대상이 되는 만큼 위험합니다.

브루트 포스 공격이란? 무차별 대입공격이란 뜻으로 성공할 때까지 가능한 모든 조합의 경우의 수를 시도해 원하는 공격을 시도하는 것으로 대표적인 예로 크렉 등 소프트웨어를 이용하여 password를 추측하는 방법입니다.

대표적인 공격 프로그램으로는 무식하게 password를 다양하게 대입하는 것과 사전을 통해 공격 시도하는 Brutus 프로그램이 있습니다. 특별한 해시 알고리즘을 사용한다 하더라도 로그인 시도 실패 횟수 초과시 강제적으로 로그인 시도를 제한하는 방법 또한 좋은 예입니다.

string hash ( string $algo , string $data [, bool $raw_output= false ] ) (PHP 5 >= 5.1.2, PECL hash >= 1.1)

요즘은 리눅스나 공인인증서 등 암호화가 필요한 곳에 보다 진보된 해시로 많이 교체되고 있습니다. 대략 해시 종류는 다음 표를 참고하면 됩니다.
 
 해시 자릿수
 md2  32
 md4  32
 md5  32
 sha1  40
 sha224  56
 sha256  64
 sha384  96
 sha512  128
 ripemd128  32
 ripemd160  40
 whirlpool  64
 tiger128,3  80
 tiger160,3  128
 tiger192,3  32
 tiger128,4  40
 tiger160,4  48
 tiger192,4  32
 snefru  40
 gost  48
 adler32  64
 crc32  64
 crc32b  64
 haval128,3  8
 haval160,3  8
 haval192,3  8
 haval224,3  128
 haval256,3  128
 haval128,4  32
 haval160,4  40
 haval192,4  48
 haval224,4  56
 haval256,4  64
 haval128,5  32
 haval160,5  40
 haval192,5  48
 haval224,5  56
 haval256,5  64

문자열 'test'를 md5 로 암호화하고, 한번 더 암호화 해줍니다.

예제(ex #1
 <?php
 echo hash('sha512''passwd_' . hash('md5''test'
));
 ?>

다음 예제로 다양한 해시 알고리즘의 결과를 확인할 수 있습니다.

예제(ex #2
 <?php 
 $data 
"test"
;  
 foreach (
hash_algos() as $v
) { 
        
$r hash($v$datafalse
); 
        
printf("%-12s %3d %s\n"$vstrlen($r), $r
); 
 } 
 ?>
 해시 자릿수 암호화
 md2 32 dd34716876364a02d0195e2fb9ae2d1b
 md4 32 db346d691d7acc4dc2625db19f9e3f52
 md5 32 098f6bcd4621d373cade4e832627b4f6
 sha1 40 a94a8fe5ccb19ba61c4c0873d391e987982fbbd3
 sha224 56 90a3ed9e32b2aaf4c61c410eb925426119e1a9dc53
d4286ade99a809
 sha256 64 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b
822cd15d6c15b0f00a08
 sha384 96 768412320f7b0aa5812fce428dc4706b3cae50e02a64
caa16a782249bfe8efc4b7ef1ccb126255d196047dfe
df17a000a9
 sha512 128 ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772
e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc8
87fd67b143732c304cc5fa9ad8e6f57f50028a8ff
 ripemd128 32 f1abb5083c9ff8a9dbbca9cd2b11fead
 ripemd160 40 5e52fee47e6b070565f74372468cdc699de89107
 ripemd256 64 fe0289110d07daeee9d9500e14c57787d9083f6ba1
0e6bcb256f86bb4fe7b981
 ripemd320 80 3b0a2e841e589cf583634a5dd265d2b5d497c4cc44b
241e34e0f62d03e98c1b9dc72970b9bc20eb5
 whirlpool 128 b913d5bbb8e461c2c5961cbe0edcdadfd29f068225
ceb37da6defcf89849368f8c6c2eb6a4c4ac75775d03
2a0ecfdfe8550573062b653fe92fc7b8fb3b7be8d6
 tiger128,3 32 8d1fd829fc83b37af1e5ba697ce8680d
 tiger160,3 40 8d1fd829fc83b37af1e5ba697ce8680d1d8bc430
 tiger192,3 48 8d1fd829fc83b37af1e5ba697ce8680d1d8bc430d76
682f1
 tiger128,4 32 f5cb297b5c37b5149de5409a190ae7f9
 tiger160,4 40 f5cb297b5c37b5149de5409a190ae7f949528b21
 tiger192,4 48 f5cb297b5c37b5149de5409a190ae7f949528b21dff1
d5d4
 snefru 64 8d25dd0b5715f7e4c799ade3a34b5f6148d0ce41699
2b5c2eaf614d35d5b3d30
 snefru256 64 8d25dd0b5715f7e4c799ade3a34b5f6148d0ce41699
2b5c2eaf614d35d5b3d30
 gost 64 a6e1acdd0cc7e00d02b90bccb2e21892289d1e93f62
2b8760cb0e076def1f42b
 adler32 8 045d01c1
 crc32 8 accf8b33
 crc32b 8 d87f7e0c
 salsa10 128 64f0dae5b7799f3389ef65e8ee02612c8e0f363b497c
6061a4e051952b03be7dc13db5fa56dd3ad9e76eae
7bfe17ba3330492d7d5f59a208e13840eee261240c
 salsa20 128 13a1ede976bd3f48a49aac1cafcf2caf88958aa37b18
440
a48dac7e27d62a54f2a8234b0b9fa9f578df36c2b946
01218510ec9d446a2ea27f73f2b9fd5b2d655
 haval128,3 32 a26075021e24a5bda74794d85e9fdb7f
 haval160,3 40 858c2c8f76afa7dd067d3d94c667c8aec6ac2650
 haval192,3 48 c4b8741917dabc27e2bebf58a6663a05b0d3dc4307
2a64b4
 haval224,3 56 f5b30a47580d8bfa256d6ed7604ffd2bb787abb22b5
3ad9f693e8d31
 haval256,3 64 593c9aed973bb51a3c852fb4e051d7c26686b9468b
4e405350cb6805dc1b99e6
 haval128,4 32 1ba3b2186ad54d024603d61ddb9d2f42
 haval160,4 40 516d3243a12ce3af38a005003c7221bf85299714
 haval192,4 48 16ff6de6751cb654c1f788ee2f14ceddb86eec343ef8
7cd5
 haval224,4 56 deea192a84b5e29ab958202b22a0b604c1df1298ee7
d32
ee5d7e2954
 haval256,4 64 435ded7266cba07f389d6e74c954b184e1ddacc8a7
b8dc022db3ca4450a738cd
 haval128,5 32 f5b480f6965efd5f5e6232925c5eed14
 haval160,5 40 f5e3770031ebc6c46fe78d92890e17b1bef93b87
 haval192,5 48 527383196142f6f3352f8a152dd06c9c0a50efcb83a6
46f0
 haval224,5 56 9666797abc57d096c2a9922e350390437f9c2e378ce
2e43e0d816d90
 haval256,5 64 a4b59d68e0111000856baca9e6573a2adc2b56b6b4
d87f7cf31de24a77b93768
 
단방향 sha1 함수

만약, php 5.1.2 이하 버전이라면, sha1 함수를 사용해도 됩니다. 분명 md5 보다는 진보된 함수입니다.

string sha1 ( string $str [, bool $raw_output ] ) (PHP 4 >= 4.3.0, PHP 5)

선택적인 raw_outputTRUE로 설정하면, 길이 20 인 바이너리 형식의 sha1 해시를 반환합니다. 기본값은 FALSE입니다.

예제(ex #3
 <?php
 $str 
'apple'
;
 if (
sha1($str) === 'd0be2dc421be4fcd0172e5afceea3970e2f3d940'
) {
    echo 
"Would you like a green or red apple?"
;
 }
 ?>

패스워드 뿐 아니라 아이디 역시 영문, 숫자를 강제적으로 포함하게 하여 보안을 강화시켜야 하고, 로그인 시도 실패 횟수를 제한해 둘 필요가 있습니다.

 관련글: 2011/09/30 - [mysql] PASSWORD 함수
            2011/09/30 - [mysql] MD5, SHA1 단방향 암호화 함수
            2011/09/14 - [mysql] 데이터의 암호화, 복호화하는 AES 함수
블로그 이미지

하보니

하보니와 함께하는 phP 초보

Tag 암호화

댓글을 달아 주세요

SQL 질의 공격이 현실적으로 많은 문제점을 가져 온다는 점에 최신 버전(MYSQL, MSSQL..)에서 자체적으로 필터링하고 있지만, 구버전에서 그렇지 못합니다.

SQL 질의를 신뢰할 수 없는 명령으로 인해 SQL 질의에서 접근 제어를 우회할 수 있여, 일반적인 인증과 인증 확인을 무시하고, 종종 SQL 질의가 사용자가 가질 수 없는 권한을 강제 취득하기도 합니다.

SQL 명령 인젝션이란? 공격자가 숨겨진 데이터를 노출하거나, 취약한 부분을 덮어쓰거나, 데이터베이스에 위험한 시스템 단계 명령을 실행하게 하는 SQL 명령을 생성하거나 대체하는 기술를 말합니다.

어플리케이션이 사용자 입력을 받아서, 이를 SQL 질의를 만들 떄 정적 인수로 조합함으로써 일어납니다. 유감스럽게도, 아래 예제들은 실제의 것입니다.

패스워드를 얻는 방법 중 하나는 검색 결과 페이지를 우회하는 것입니다. 공격자에게 필요한 것은 변수 중 하나라도 제대로 다뤄지지 않으면서 SQL 구문에 사용되는 것입니다.

이러한 필터는 일반적으로 SELECT 구문에서 WHERE, ORDER BY, LIMIT, OFFSET에 사용됩니다. 데이터베이스가 UNION 구조를 지원하면, 공격자는 원래 질의에 전체 질의를 덧붙여서 임의의 테이블에서 패스워드를 얻을 수 있습니다. 암호화된 패스워드 필드를 강력히 권합니다.

SQL 질의 공격


검증되지 않는 변수를 전적 사용자의 신뢰를 믿고 필터링하지 않는다면, 문제는 커질 수 밖에 없습니다. 다음 변수에 이 질의('--로..)가 $query 에서 사용하는 변수 중 하나에 할당되면, 문제는 커질 수 밖에 없습니다.

예제 (ex #1

 <?php
 $query  
"SELECT id, name, inserted, size FROM products
                  WHERE size = '
$size
'
                  ORDER BY 
$order LIMIT $limit$offset;"
;
 $result mysql_query($query
);
 ?>

다음 질의로 비밀번호없이 누구나 접속이 가능하게 변질되어 버립니다.

예제 (ex #2
 <?php
 $_POST['username'] = 'aidan';
 $_POST['password'] = "' OR ''='"
;

 $query "SELECT * FROM users WHERE user='{$_POST['username']}'
            AND password='
{$_POST['password']}'"
;
 mysql_query($query
);

 echo $query;
 // 결과: SELECT * FROM users WHERE user='aidan' AND password='' OR ''=''
 ?>

SQL UPDATE도 공격받을 수 있는데, 이런 질의를 완전한 새 질의를 덧붙일 수 있습니다. 또한 공격자가 SET 절을 다룰 수도 있습니다. 이 경우 질의를 성공적으로 변경하기 위하여 일부 스키마 정보를 가지고 있어야 합니다.

예제 (ex #3
 <?php
 $query "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";
 ?>
 

악의적인 사용자가 $uid ' or uid like'%admin'; -- 값을 넣어서 관리자 패스워드를 변경하거나, $pwd "hehehe', admin='yes', trusted=100 "(마지막 공백 포함)을 설정하여 권한을 얻을 수도 있습니다.

예제 (ex #4
 <?php
 // $uid == ' or uid like'%admin%'; --
 $query "UPDATE usertable SET pwd='...' WHERE uid='' or uid like 
'%admin%'; --"
;

 // $pwd == "hehehe', admin='yes', trusted=100 "
 $query 
"UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100
 WHERE ...;"
;
 ?>

데이터베이스 호스트의 OS 등급 명령에 접근하는 문제시 될 예제입니다.

예제 (ex #5
 <?php
 $query  
"SELECT * FROM products WHERE id LIKE '%$prod%'"
;
 $result mssql_query($query
);
 ?>

공격자가 $proda%' exec master..xp_cmdshell 'net user test testpass /ADD' -- 값을 제출하면, $query는:

예제 (ex #6
 <?php
 $query  
"SELECT * FROM products
             WHERE id LIKE '%a%'
             exec master..xp_cmdshell 'net user test testpass /ADD'--"
;
 $result mssql_query($query
);
 
?>

이러한 공격은 주로 보안을 염두에 두지 않고, 쓰여진 코드 취약점에서 발생합니다. 어떠한 입력도 믿어서는 안되며, 최신 버전이라도 한번더 필터링해 주어야 합니다.

특히 클라이언트측에서 오는 입력은 믿어서는 안됩니다. select, hidden input 필드, 쿠키도 마찬가지입니다. 첫 번째, 두 번째 예제에서 그러한 질의가 큰 문제를 일으킬 수 있음을 보여주고 있습니다.

SQL 인젝션 회피


다음은 안전한 질의 예제가 됩니다.

예제 (ex #7

 <?php
 settype
($offset'integer'
);
 $query "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET
               
$offset;"
;

 $query sprintf("SELECT id, name FROM products ORDER BY
                    name LIMIT 20 OFFSET %d;"
$offset);
 ?>

이러한 문제를 회피하기 위해 안전한 방법으로 문자열 회피 함수를 사용하는 것인데, mysql_real_escape_string() 가 그것입니다. mysql_real_escape_stringmysql_query 에서 특수 문자열을 이스케이프하기 위해 사용되며, 그러므로 SQL 인젝션 공격이 동작하지 않고 질의가 정확하게 실행될 것입니다.

예제 (ex #8

 <?php
 if (isset($_POST['product_name']) &&
       isset(
$_POST['product_description']) &&
       isset(
$_POST['user_id'
])) {
    
// 접속
    
$link mysql_connect(
     
'mysql_host',
     
'mysql_user',
     
'mysql_password'

    );
    if(!
is_resource($link
)) {
        echo 
"서버 접속 실패\n"
;
        
// ... 오류를 적절히 기록
    
} else {
        
// ON일 경우 magic_quotes_gpc/magic_quotes_sybase 효과 제거
        
if(get_magic_quotes_gpc
()) {
            
$product_name        =
                stripslashes
($_POST['product_name'
]);
            
$product_description =
               
stripslashes($_POST['product_description'
]);
        } else {
            
$product_name        $_POST['product_name'
];
            
$product_description $_POST['product_description'
];
        }
        
// 안전한 질의 만들기
        
$query sprintf("INSERT INTO products (
                          `name`, `description`, `user_id`)
                           VALUES ('%s', '%s', %d)"
,
              
mysql_real_escape_string($product_name$link
),
              
mysql_real_escape_string($product_description$link
),
              
$_POST['user_id'
]);

        
mysql_query($query$link
);

        if (
mysql_affected_rows($link) > 0
) {
            echo 
"Product inserted\n"
;
        }
    }
 } else {
    echo 
"Fill the form property\n"
;
 }
 ?>


아니면 addslashes() str_replace() 함수를 사용할 수도 있습니다. addslashes() 는 데이터베이스 질의 등에서 처리할 필요가 있는 문자 앞에 백슬래시를 붙인 문자열을 반환합니다. 이 문자들은 작은 따옴표('), 큰 따옴표("), 백슬래시(\), NUL(NULL 바이트)입니다.

addslashes()를 사용하는 대표적인 예는 데이터베이스에 데이터를 넣을 때 입니다. 예를 들어, 데이터베이스에 O'reilly 라는 이름을 넣으려고 할때, 이스케이프할 필요가 있습니다. 대부분의 데이터베이스는 \을 사용하기에 O\'reilly가 되어야 합니다. 이 데이터를 데이터베이스에 넣으면 추가한 \은 저장되지 않습니다.

예제 (ex #9
 <?php
 $str 
"Is your name O'reilly?"
;

 // 출력: Is your name O\'reilly?
 echo addslashes($str
);
 ?>


블로그 이미지

하보니

하보니와 함께하는 phP 초보

Tag 암호화

댓글을 달아 주세요

mysql 에는 데이터를 암호화, 복호화하는 AES_ENCRYPT, AES_DECRYPT 함수가 있습니다. 이 암호화는 128비트 길이로 인코딩되어 저장됩니다. 그러나 소스를 수정해서 256비트까지 확장시킬수 있다고 합니다.

AES_ENCRYPT 는 문자열을 암호화하고, 바이너리 문자열을 반환하지만, AES_DECRYPT 는 암호화된 문자열을 복호화합니다. AES_DECRYPT 는 유효하지 않은 데이터는 padding을 감지하고, NULL을 반환합니다.

 # "암호화 키"는 임의의 값이 올 수 있으며, "문자열"은 암호화하고자 하는 값이 됩니다.

 # AES_ENCRYPT 암호화
  INSERT INTO 테이블명 VALUES (HEX(AES_ENCRYPT('문자열', '암호화 키')));
 
 # AES_DECRYPT 복호화
  SELECT AES_DECRYPT(UNHEX(필드명), '암호화 키') FROM 테이블명;

예제 (ex #1
 # AES_ENCRYPT 암호화
 INSERT INTO tbname VALUE (HEX(AES_ENCRYPT('123456','가나다라')));
 // 결과: 5A33E11DC0B638E4E5E74EBD52F55E3D

 # AES_DECRYPT 복호화
 SELECT AES_DECRYPT(UNHEX(필드명), '가나다라') FROM tbname;

 관련글: 2011/09/30 - 브루트 포스 공격 (brute force attack)
            2011/09/30 - [mysql] MD5, SHA1 단방향 암호화 함수
            2011/09/30 - [mysql] PASSWORD 함수
블로그 이미지

하보니

하보니와 함께하는 phP 초보

Tag 암호화

댓글을 달아 주세요

string base64_encode ( string $data ) (PHP 4, PHP 5)

이 함수는 모든 정보를 64개 문자로 구성된 64진수로 바꾸는 것으로 a-z, A-Z, 0-9, +, / 의 문자이며, 암호화 방식과는 거리가 멀고, 데이터보다 33% 많은 공간을 필요로 합니다.

예제 (ex #1
 <?php 
 $str 
'This is an encoded string'

 echo 
base64_encode($str
); 
 
// 결과: VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw== 
 
?>

64 문자는 = 포함한 문자인데, = 단순히 4자리 수를 맞춰 공간을 채우는 의미 없는 문자이므로 신경쓰지 않아도 됩니다.

 

인코딩은 메일 본문처럼 8비트를 사용할 없는 전송 층에서 바이너리 데이터를 안전하게 전송하도록 설계되었습니다.

 

다만, GET이나 REQUEST 전송시 +, / 문자가 문제시 되므로 urlencode 데이터를 보호하거나 다음과 같이 치환해서 데이터를 보호해줄 필요가 있습니다.

예제 (ex #1

 <?php
 
function base64encode($string) { 
    
$data str_replace(array('+','/','='),array('-','_',''),base64_encode($string)); 
    return 
$data
 } 

 function 
base64decode($string) { 
    
$data str_replace(array('-','_'),array('+','/'),$string); 
    
$mod4 strlen($data) % 4
    if (
$mod4) { 
        
$data .= substr('===='$mod4); 
    } 
    return 
base64_decode($data); 
 } 

 
$string '1234567890가나다라마바사'
 
$data base64encode($string); 

 echo 
$data// 결과: MTIzNDU2Nzg5MLChs6q02bbzuLa52bvn 
 
echo '<br />'

 echo 
base64decode($data); // 결과: 1234567890가나다라마바사 
 
?>

관련글:  2011/08/30 - Base64 인코딩 원리
            2011/08/09 - 문자열 URL 인코드 함수
            2011/05/29 - 패스워드 스니핑

블로그 이미지

하보니

하보니와 함께하는 phP 초보

댓글을 달아 주세요

문자열을 인코드하는 함수는 urlencode, rawurlencode 가 있습니다.  rawurlencode 함수는 -_.을 제외한 모든 영숫자가 아닌 문자를 퍼센트(%) 사인에 이어지는 두 16진수로 교체한 문자열을 반환합니다.

이는 표시 문자가 특별한 URL 구분자로 해석되는 걸 방지하고, 문자 변환이 이루어지는 몇몇 email 시스템 등에서 URL을 보호하기 위한 수단으로 이용됩니다.

urlencode 는 공백을 더하기 부호(+)로 인코드 하는 점 말고는 rawurlencode 와 동일한 기능을 제공합니다.

예제 (ex #1
 <?php
 
// ex #1
 
$foo '"/:@&%=?.#"'
;
 
$bar '#$%=+'
;
 
$query_string 'foo=' urlencode($foo) . '&bar=' urlencode($bar
);
 echo 
'<a href="mycgi?foo=' htmlentities($query_string) . '">'
;
 
// 결과: <a href="mycgi?foo=foo=%22%2F%3A%40%26%25%3D%3F.%23%22&amp;bar=%23%24%25%3D%2B">

 // ex #2
 
$userinput 'test.php?/mycgi'
;
 echo 
'<a href="mycgi?foo='urlencode($userinput), '">'
;
 
// 결과: <a href="mycgi?foo=test.php%3F%2Fmycgi">
 
?>

예제 (ex #2
 <?php 
 $url
= ""
;
 for(
$i = 0; $i < strlen($value); $i
++) {
     
$url .= strpos("/:@&%=?.#", $value[$i]) === False ? urlencode($value[$i]) : $value[$i
];
 }

 ?>

예제 (ex #3
 <?php
 function fullescape($in
){
     
$out = ''
;
      for (
$i=0;$i<strlen($in);$i
++) {
          
$hex = dechex(ord($in[$i
]));
           if (
$hex==''

             
$out = $out.urlencode($in[$i
]);
           else 
             
$out = $out .'%'.((strlen($hex)==1) ? ('0'.strtoupper($hex)):(strtoupper($hex
))); 
      }
     
$out = str_replace('+','%20',$out
);
     
$out = str_replace('_','%5F',$out
);
     
$out = str_replace('.','%2E',$out
);
     
$out = str_replace('-','%2D',$out
);
  return
$out
;
 }
 ?>

예제 (ex #4
 <?php
 $url
= "index.php?id=4&pg=2"
;
 
$url = urlencode(urlencode($url
));

 echo
"<a href=\"javascript:openWin('page.php?url=$url');\">"
;
 ?>

예제 (ex #5
 <?
 $url
='mypage.php'
;
 ?>
 <a href="index.php?page=<? echo encode($url,5); ?>">My page</a>

 <?
 $mypage
=$_GET['page'
];
 $mypage=decode($mypage,5
);
 echo 
file_get_contents($mypage
);

 function 
encode($ss,$ntime
){
    for(
$i=0;$i<$ntime;$i
++){
        
$ss=base64_encode($ss
);
    }
 retrun $ss
;
 }

 function 
decode($ss,$ntime
){
    for(
$i=0;$i<$ntime;$i
++){
        
$ss=base64_decode($ss
);
    }
 retrun $ss
;
 } 
 
?>

다음은 FTP url를 인코드합니다.

예제 (ex #6
 <?php
 echo '<a href="ftp://user:'rawurlencode('foo @+%/'
), '@ftp.example.com/x.txt">';
 // 결과: <a href="ftp://user:foo%20%40%2B%25%2F@ftp.example.com/x.txt">
 ?>

URL의 PATH_INFO 안에 경로 정보를 전달하고자 한다면, 다음과 같이 처리해 줍니다.

예제 (ex #7
 <?php
 echo '<a href="http://example.com/department_list_script/',
         
rawurlencode('sales and marketing/Miami'), '">'
;
 // 결과: <a href="http://example.com/department_list_script/sales%20and%20marketing%2FMiami">
 ?>

참고로 url 디코드 함수는 주어진 문자열의 %## 인코딩을 디코드해 줍니다. 다만, $_GET 이나 $_REQUEST 변수에는 이미 디코드되어 있어서 따로 디코드할 필요는 없지만, 디코드 할 경우 우리가 원하지 않는 결과를 가져오는 점에 주의가 필요합니다.

관련글:  2011/08/30 - 64진수로 암호화하는 base64 함수
블로그 이미지

하보니

하보니와 함께하는 phP 초보

Tag 암호화

댓글을 달아 주세요

크로스 사이트 스크립팅(cross-site scripting, 영문 약어 XSS)은 웹 페이지에 클라이언트 사이드 스크립트를 삽입하여 다른 사용자가 이를 실행하게끔 허용하는 취약점으로, 웹에서 사용되는 대표적 스크립트 언어로 자바스크립트, VB스크립트가 있습니다.

이 취약점은 사용자로부터 입력 받은 값을 제대로된 검사를 하지 않고 그대로 사용할 경우 나타나는데, 주로 사용자의 정보(GET, POST, COOKIE, SESSION 등)를 탈취하기 위하여 특수 문자나 예약어, 스크립트를 나타내는 (, ), !, @, {, }, \n, \t, \0, ', " , > , < , % , $ 등의 문자를 이용합니다.

공격 대상 웹사이트에 삽입한 스크립트를 이용하여 다른 웹사이트로 접근하는 것도 가능하기 때문에 사이트 간 스크립팅이라고 합니다.

매월 크로스 사이트 스크립팅 공격이 상용 사이트에서 발생하고 그러한 위험성을 설명하는 경고문이 발표된다고 합니다. 주의하지 않는 다면 여러분의 웹 사이트나 회사도 이러한 공격의 희생양이 될 것입니다.


웹사이트 공격


크로스 사이트 스크립팅으로 인해 다음과 같은 위험에 빠지게 됩니다.
  • 웹 사이트상의 애플리케이션이 크로스 사이트 스크립팅에 취약하다고 알려지면 공격자는 공격 목표의 권한을 사용하여 실행할 수 있도록 JavaScript, VBScript, ActiveX, HTML, Flash를 투입하는 것입니다. 공격이 활성화 되면 계정 하이재킹, 사용자 설정 변경, 쿠키 훔치기 및 오염, 오류 광고 등이 가능하게 됩니다.

  • 공격자는 사용자 세션, 쿠키가 종료되기 전에 사용자 세션을 인계 받을 수 있으며, 공격자가 제공한 URL로 사용자가 접근할 수 있도록 할 수 있는 침입자는 공격자가 선택한 스크립트나 HTML이 사용자 브라우저에서 실행될 수 있도록 할 수 있고, 이러한 기술을 사용하여 공격자는 URL로 접근했던 사용자의 권한을 사용하여 액션을 취할 수 있습니다. SQL 데이터베이스에 쿼리를 실행하거나 결과를 보고 목표 시스템 구현의 오류를 악용할 수도 있습니다.

공격 샘플


다음과 같이 제대로 된 검사를 하지 않는다면, 공격자는 얼마든지 공격삽입이 가능합니다.

 <?php 
 $search 
"'><script>alert(123)</script><'"
;  
 
?> 
 <input ~~ value='<?=$search?>'> 

위와 같이 필터를 거치지 않는 다면 다음과 같은 결과를 만들어 냅니다.

 <input ~~ value=' '><script>alert(123)</script><' '>

필터를 처리하기 위해 다음과 같이 한줄 코드를 삽입하여 공격을 회피할 수 있습니다. 

 <?php 
 $search 
"'><script>alert(123)</script><'"
;  
 
?> 
 <input ~~ value='<?=htmlspecialchars($search)?>'> 

다음은 필터 처리된 모습니다.

  <input ~~ value=''&gt;&lt;script&gt;alert(123)&lt;/script&gt;&lt;''> 

다음은 대표적 링크삽입 공격입니다.

 <?php 
 $_GET
['link'] = "'<SCRIPT>malicious code</SCRIPT>'"
;  
 
?> 
 <A HREF=http://test.com/list.cgi?clientprofile=<?=$_GET['link']?>>Click here</A> 

이 역시 다음 코드 한줄로 필터가 가능합니다.

 <?php 
 $_GET
['link'] = "'<SCRIPT>malicious code</SCRIPT>'"
;  
 
?> 
 <A HREF=http://test.com/list.cgi?clientprofile=<?=urlencode($_GET['link'])?>>Click here</A>

결과 모습입니다.

 <A HREF=http://test.com/list.cgi?clientprofile=%27%3CSCRIPT%3Emalicious+code%3C%2FSCRIPT%3E%27>Click here</A>

이러한 접근 방식의 기초는 사용자 input 나 link 를 절대 신뢰하지 말고 HTML 스팩에서 정의된 메타문자("특수" 문자)를 언제나 필터링 하여 스크립트를 보호하는 것입니다.

그리고 쿠키나 세션으로 데이터를 구울때 중요 데이터인 경우 암호화하여 혹여나 데이터 유출시 쉽게 알아보지 못하게 해둘 필요가 있어 암호화기법도 중요합니다.
블로그 이미지

하보니

하보니와 함께하는 phP 초보

Tag 암호화

댓글을 달아 주세요

리플레이 공격방식은 프레젠테이션 공격이라 부르는데, 정상적인 사용자가 인증권한을 취득하기 위해 전송한 데이터를 재전송하는 모든 종류의 공격을 말합니다. 리플레이 공격과 마찬가지로 패스워드 스니핑 공격을 차단하려는 노력은 많지만 완전 차단방법은 없습니다.

그렇기 때문에 인증과정 중 폼의 여러 가지 속성을 설치한다 하여 공격자에게는 그다지 중요하지 않다 생각되는 잡다한 것으로 보며, 그래서인지 요즘은 HTTP요청내용과 HTTP응답내용이 노출되지 않게 보호하려는 방법으로 SSL전송방식을 많이 애용하는 편입니다. 허나 누가 뭐라해도 패스워드를 보호하는 일이야 말로 가장 중요한 부분임을 누구도 거부하지 않습니다.

이제는 _POST방식도 인증보호에 기대가 없고, 그렇다고 MD5도 믿음이 있어 보이지 않습니다. 왜냐하면 몇 년전에 이미 MD5가 복호화되어 암호가 뚤려 버렸기 때문입니다.

 <form action=https://mydomain.com/login.php method="POST"><br />
 myid:     <input type="text" name="username"><br />
 mypass:<input type="password" name="userpass"><br />
 </form> 

개인이 호스팅을 임대받는 경우라면 SSL기능을 자유롭게 사용할 수 없는 입장이므로 _GET전송방식보다는 인증노출이 적은 _POST방식을 많이 사용할 것을 권장하며, 비밀번호는 입력받아 MD5로 암호화하되 복잡한 암호를 사용하도록 사용자에게 유도하거나 개발자가 임의의 문자를 섞여 한번 더 암호화시켜 주어야 합니다.

다음으로 인증요청 무차별 공격 스크립트를 작성할 수 있습니다.

 <form action="http://mydomain.com/login.php" method="POST"><br />
 myid:     <input type="text" name="username"><br />
 mypass:<input type="password" name="userpass"><br />
 </form> 

 
<?php
 $host 
"mydomain.com"
;
 
$username "habony"
;
 
$userpass "1111"
;

 
$data "username=$username&userpass=$userpass"
;
 
$len strlen($data
);


 
// 헤더 구분은 \r\n로 해주어야 합니다.
 
$request ''
;
 
$request .= "POST /login.php HTTP/1.1\r\n"
;
 
$request .= "Host: ${host}\r\n"
;
 
$request .= "Content-Type: application/x-www-form-urlencoded\r\n"
;
 
$request .= "Content-Length: ${len}\r\n"
;
 
$request .= "Connection: close\r\n"
;

 
// 본문시작은 \r\n\r\n로 헤더와 바디로 구분합니다.
 
$request .= "\r\n"
;
 
$request .= "$data"
;

 
// HTTP요청은 기본 80포트입니다.
 
if($fp fsockopen($host80
)){
      
// mydomain.com 에 HTTP요청하고, HTTP응답을 받습니다.
      
fputs($fp$request
);

      
$response ''
;
      while(!
feof($fp
)){
            
// 1줄씩 응답을 읽어 옵니다.
           
$response .= fgets($fp1024
);
      }
      
fclose($fp
);
 }

 echo 
"$response<br />\n"
;

 
?>

이와 같은 작업으로 공격자는 인증시도를 하려할 것인데, $response의 결과에 따라 패스워드 취득 실패시 다른 패스워드 재시도 루틴을 요청할 수 있을 것입니다. 만약 사용자가 복잡한 암호를 구성하였다면, 공격자의 성공확률을 낮출 수 있습니다.

사용자 암호보호를 위해 암호화하는 것은 필요한 것이므로 무차별 공격을 어렵게 만들거나 성공확률을 낮추기 위해 30초정도 지연시킬 수 있습니다.

 <?php
 $uniqid 
uniqid(rand
());
 
// 아이디에 위험한 문자열이 있을 경우 ...
 
$inputid mysql_real_escape_string($_POST['inputid'
]);
 
// 사용자가 단순한 암호를 선택하였다면,
 // 개발자가 임의 문자를 붙여 한번 더 암호화시켜줍니다.
 // md5 함수는 16진수 32 문자로 반환합니다.
 // 16진수 32문자 = md5(문자열, [raw_output]);
 // raw_output는 PHP 5.0부터 사용 가능하며,
 // true로 설정하면 길이 16의 바이너리 형식으로 반환합니다.
 // md5는 문자열 암호화이고, md5_file는 파일 암호화로 동일하게 사용할 수 
있습니다.
 // echo md5("myid"); // 결과:cdce51bb5b16a770fbe0dd78e6d8a5bb
 // echo md5("myid", true); // 결과: 誥Q?&#52025;鎬?燕?
 
$inputpass md5($uniqid "_habony_" md5("habony_" 
$_POST['inputpass'], true
));

 

 
$data 
= array();
 
$sql 
= array();

 
$now time
();
 
$login_conn $now 30
;

 if(
$sql mysql_query("select logintime, inputpass from $db where 
inputid='${inputid}'"
)){
      if(
mysql_num_rows($sql
)){
           
$row mysql_fetch_assoc($sql
);
           if(
$row['logintime'] > $login_conn
){
                exit(
"로그인 실패하여 30초가 지나야 로그인 가능합니다."
);
           } elseif(
$row['inputpass'] === $inputpass
){
                echo 
"로그인 인증되었습니다."
;
           } else {
               
// 로그인 실패시 처리 부분...
                
mysql_query("update $db set logintime = '$now' where 
inputid = '$inputid' "
);
           }
      }  else {
           exit(
"해당하는 아이디가 없습니다."
);
      }
 }
 
?>


파일업로드된 파일접근을 막기 위해 이것 역시 암호화하여 저장할 필요가 있습니다.

 <?php
 $uniqid 
uniqid(rand
());
 
// 16진수 32문자 = md5_file(파일명, [raw_output]);
 // raw_output는 PHP 5.0부터 사용 가능하며,
 // true로 설정하면 길이 16의 바이너리 형식으로 반환합니다.
 // md5_file함수는 파일이 실제 존재해야 암호화됩니다.
 // 실패하면 php오류코드를 표시합니다.
 // md5_file은 다음과 같은 조건입니다.
 // if(file_exists($filename)){
 //      $md5filename = md5($uniqid . "_habony_". md5($filename, true));
 // }
 
$filename base64_encode($_FILES['userfile']['name'
]);
 
$md5filename md5($uniqid "_habony_"md5_file($filenametrue
));
 if(
$_FILES['userfile']['error'] === UPLOAD_ERR_OK
) {
      if(
$_FILES['userfile']['size'] <= 0
){
          echo 
"파일 업로드에 실패하였습니다."
;
      } else {
          
// HTTP post로 전송된 것인지 체크합니다.
          
if(!is_uploaded_file($_FILES['userfile']['tmp_name'
])) {
               echo 
"HTTP로 전송된 파일이 아닙니다."
;
          } else {
               
// move_uploaded_file은 임시 저장되어 있는 파일을 ./uploads 디렉토리로 이동합니다.
               
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $md5filename
)) {
                    echo 
"성공적으로 업로드 되었습니다.\n"
;
               } else {
                    echo 
"파일 업로드 실패입니다.\n"
;
               }
               
mysql_query(
"insert into $db values  ('','$filename');
          }
      }
 } else {
      echo file_errmsg($_FILES['userfile']['error']);
 }
 ?>


블로그 이미지

하보니

하보니와 함께하는 phP 초보

댓글을 달아 주세요

  • MD5 2011.09.27 22:30  댓글주소  수정/삭제  댓글쓰기

    MD5가 뚫렸다는게 해시에서 원본을 찾아낼수 있게 뚫렸다는게 아닙니다.
    해시는 기본적으로 강한 충돌저항성을 가지는데 임의로 충돌을 만들어 내는데 성공했다고 합니다.
    이를 이용하면 예를들어 가짜 인증서를 만들수 있겠죠...

  • MD5 2011.09.27 22:31  댓글주소  수정/삭제  댓글쓰기

    일단 간단한 암호의 경우에는 브루트포스나 레이보우테이블을 이용해서 뚫는게 가능합니다.
    다만 충분히 강한 SOLT를 붙이면 훨씬 뚫기 힘들어지겠죠...

    • Favicon of https://blog.habonyphp.com BlogIcon 하보니 2011.09.28 18:17 신고  댓글주소  수정/삭제

      단순히 [a-z 0-9]로 이루어진 문자로는 보안이 약하다는 뜻이네요. 중간에 특수문자를 섞어두면 좀 안심이 되지 않을까요?

      조은 정보 감사합니다.

php는 POST로 파일 업로드기능을 제공합니다. RFC-1867 호환 브라우저(넷스케이프 네비게이터 3 이상, 마이크로소프트 인터넷 익스플로러 3+패치나 패치 없이 그 이상 버전을 포함)라면 파일 업로드를 받을 수 있는 기능을 제공합니다.

다음 표의 내용을 php.ini에서 조작할 수 있습니다.

 옵션  의미
 file_uploads

 업로드 기능을 사용할지를 결정합니다. 기본값 On

 upload_tmp_dir  업로드시 임시 저장 될 디렉토리 경로
 upload_max_filesize  허용하는 최대 파일 크기, 기본값 100M
 max_file_uploads  허용하는 최대 업로드 수, 기본값 100개

파일 업로드 폼은 다음 표처럼 작성하되 폼 안에 enctype="multipart/form-data"값이 있는지 확인하여야 합니다. 그렇지 않으면 업로드 기능은 작동하지 않습니다.

 <form enctype="multipart/form-data" action="send_ok.php" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
    이 파일을 전송합니다: <input name="userfile" type="file" />
    <input type="submit" value="파일 전송" />
 </form>

method는 post로 정의하며, MAX_FILE_SIZE는 php.ini에 지정된 upload_max_filesize 크기 보다 클 수 는 없습니다. 이 필드는 ini에 지정된 파일크기보다 크면 에러를 표시하는 용도로만 사용되어야 합니다.

보통 하나의 파일을 업로드하면 다음 표의 변수($_FILES['파일명']['name'])를 여러개 가지게 됩니다.

 변수명  의미
 name  클라이언트측 원래 이름
 type  "image/gif"와 같은 파일의 mime형식, 그러나 php에서 확인하지 않으므로 이 값을 무시하여야 합니다.
 size  업로드된 파일의 바이트로 표현한 크기
 tmp_name
 서버에 저장된 업로드된 파일의 임시 파일 이름
 error  파일 업로드에 대한 에러 코드를 표시

파일 업로드는 다음 예제와 같은 과정으로 작성하면 됩니다.

예제 (ex #1

  <form enctype="multipart/form-data" action="" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
    이 파일을 전송합니다: <input name="userfile" type="file" />
    <input type="submit" value="파일 전송" />
 </form>

 
<?php
 
// uploads디렉토리에 파일을 업로드합니다.
 
$uploaddir './uploads/'
;
 
$uploadfile $uploaddir basename($_FILES['userfile']['name'
]);

 echo 
'<pre>'
;
 if(
$_POST['MAX_FILE_SIZE'] < $_FILES['userfile']['size'
]){
      echo 
"업로드 파일이 지정된 파일크기보다 큽니다.\n"
;
 } else {
     if((
$_FILES['userfile']['error'] > 0) || ($_FILES['userfile']['size'] <= 0
)){
          echo 
"파일 업로드에 실패하였습니다."
;
     } else {
          
// HTTP post로 전송된 것인지 체크합니다.
          
if(!is_uploaded_file($_FILES['userfile']['tmp_name'
])) {
                echo 
"HTTP로 전송된 파일이 아닙니다."
;
          } else {
                
// move_uploaded_file은 임시 저장되어 있는 파일을 ./uploads 디렉토리로 이동합니다.
                
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile
)) {
                     echo 
"성공적으로 업로드 되었습니다.\n"
;
                } else {
                     echo 
"파일 업로드 실패입니다.\n"
;
                }
          }
     }
 }

 
print_r($_FILES
);

 
/*
 결과:
 성공적으로 업로드 되었습니다.
 Array
 (
    [userfile] => Array
        (
            [name] => config.sys
            [type] => text/plain
            [tmp_name] => /tmp/phpXTtzBW
            [error] => 0
            [size] => 10
        )
 )
 */
 
?> 


파일 업로드가 성공적이면 에러코드는 0을 가집니다. 에러 코드는 다음 표의 상수로 대조해도 됩니다.

 상수명  의미
 UPLOAD_ERR_OK  값: 0; 오류 없이 파일 업로드가 성공했습니다
 UPLOAD_ERR_INI_SIZE 값: 1; 업로드한 파일이 php.ini upload_max_filesize 지시어보다 큽니다
 UPLOAD_ERR_FORM_SIZE 
값: 2; 업로드한 파일이 HTML 폼에서 지정한 MAX_FILE_SIZE 보다 큽니다. 
 UPLOAD_ERR_PARTIAL 
값: 3; 파일이 일부분만 전송되었습니다
 UPLOAD_ERR_NO_FILE  값: 4; 파일이 전송되지 않았습니다
 UPLOAD_ERR_NO_TMP_DIR  값: 6; 임시 폴더가 없습니다. PHP 4.3.10과 PHP 5.0.3에서 추가.
 UPLOAD_ERR_CANT_WRITE  값: 7; 디스크에 파일 쓰기를 실패했습니다. PHP 5.1.0에서 추가
 UPLOAD_ERR_EXTENSION  값: 8; 확장에 의해 파일 업로드가 중지되었습니다. PHP 5.2.0에서 추가.

파일 이름을 서버에 그대로 저장하는 것도 보안상 상당한 위험이 있으므로 md5로 암호화해서 저장하고, 디비에 원래 이름을 저장하도록 합니다.

예제 (ex #2

   <form enctype="multipart/form-data" action="" method="POST">
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
    이 파일을 전송합니다: <input name="userfile" type="file" />
    <input type="submit" value="파일 전송" />
 </form>

 
<?php
 
function file_errmsg($code
){
     switch(
$code
){
         case(
UPLOAD_ERR_INI_SIZE
):
         return 
"업로드한 파일이 php.ini upload_max_filesize보다 큽니다."
;
     case(
UPLOAD_ERR_FORM_SIZE
):
         return 
"업로드한 파일이 MAX_FILE_SIZE 보다 큽니다. "
;
     case(
UPLOAD_ERR_PARTIAL
):
         return 
"파일이 일부분만 전송되었습니다. 다시 시도해 주십시요."
;
     case(
UPLOAD_ERR_NO_FILE
):
         return 
"파일이 전송되지 않았습니다."
;
     case(
UPLOAD_ERR_NO_TMP_DIR
):
         return 
"임시 폴더가 없습니다."
;
     case(
UPLOAD_ERR_CANT_WRITE
):
         return 
"디스크에 파일 쓰기를 실패했습니다. 다시 시도해 주십시요."
;
     default:
         return 
"확장에 의해 파일 업로드가 중지되었습니다."
;
     }
 }

 
// 서버에 저장될 디렉토리이름
 
$uploaddir './uploads/'
;
 
// 서버에 저장될 파일이름
 
$filename basename($_FILES['userfile']['name'
]);
 
$md5filename $uploaddir md5("habony_".$filename
);
 
$ext array_pop(explode(".","$filename"
);

 echo 
'<pre>'
;
 if(
$_FILES['userfile']['error'] === UPLOAD_ERR_OK
) {
      if(
strtolower($ext) == "php"
) {
           echo 
"확장자 php파일은 업로드 하실수 없습니다."
;
      }
      else if(
$_FILES['userfile']['size'] <= 0
){
          echo 
"파일 업로드에 실패하였습니다."
;
      } else {
          
// HTTP post로 전송된 것인지 체크합니다.
          
if(!is_uploaded_file($_FILES['userfile']['tmp_name'
])) {
               echo 
"HTTP로 전송된 파일이 아닙니다."
;
          } else {
               
// move_uploaded_file은 임시 저장되어 있는 파일을 ./uploads 디렉토리로 이동합니다.
               
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $md5filename
)) {
                    echo 
"성공적으로 업로드 되었습니다.\n"
;
               } else {
                    echo 
"파일 업로드 실패입니다.\n"
;
               }
               
mysql_query("insert into $db values  ('','$filename')"
);
          }
      }
 } else {
      echo 
file_errmsg($_FILES['userfile']['error'
]);
 }

 
print_r($_FILES
);

 
/*
 결과:
 성공적으로 업로드 되었습니다.
 Array
 (
    [userfile] => Array
        (
            [name] => config.sys
            [type] => text/plain
            [tmp_name] => /tmp/phpXTtzBW
            [error] => 0
            [size] => 10
        )
 )
 */
 
?>

블로그 이미지

하보니

하보니와 함께하는 phP 초보

댓글을 달아 주세요