'Web 프로그램/암호화 처리'에 해당되는 글 5건

728x90

https://gist.github.com/joashp/a1ae9cb30fa533f4ad94 를 참조하여 AES 암호화, 복호화 알고리즘을 테스트 했다.


PHP에서 문자열을 암호화할 때 보다 더 강력하게 암호화할 수 있는 salt(솔트), hash 256를 사용한 AES 암호화, 복호화 알고리즘이다.

가장 중요한 것은 secret_key 를 관리하는 방법이다.

web 접속 경로상에 없도록 하거나, 다른 서버에 관리하는 것이 좋다.

아래 예제에서는 $salt 를 이용하여 생성한 값을 가지고 임의로 $secret_key 를 만들었다.


윈도우 기반 autoset9 에서는 openssl_encrypt 에러가 발생하여 리눅스 기반에서 테스트를 했다.


사용법 예제

<?php
include_once 'dbController.php';
require_once 'loginClass.php';
$c = new LoginClass();

$salt = sha1(mt_rand());
echo $salt.'<br />';
$secret_key = "f9a90bfa9e8ddd9965fecc0052e6786cf59f3131";
echo $secret_key.'<br />';
$secret_iv = substr($salt, 0, 20);
echo $secret_iv.'<br />';

$str = '안녕하세요? 홍길동입니다.';
$encrypted = $c->AES_encrypt($str);
echo $encrypted.'<br />';
echo 'encrypted message length : '.strlen($encrypted).'<br />';

$decrypted = $c->AES_decrypt($encrypted);
echo $decrypted.'<br />';
?>



Class

<?php
class DBController {
    private $host = 'localhost';
    private $database = 'test';
    private $userid = 'root';
    private $password = 'autoset';
    protected $db; // 변수를 선언한 클래스와 상속받은 클래스에서 참조할 수 있다.

    public function __construct() {
        $this->db = $this->connectDB();
        // construct 메소드는 객체가 생성(인스턴스화)될 때 자동으로 실행되는 특수한 메소드다.
    }

    function __destruct(){
        mysqli_close($this->connectDB());
        //mysqli_close($this->db);
    }

    private function connectDB() {
        $dbconn = mysqli_connect($this->host, $this->userid, $this->password, $this->database);
        mysqli_set_charset($dbconn, "utf8"); // DB설정이 잘못되어 euc-kr 로 되어 있으면 문제가 됨
        if (mysqli_connect_errno()) {
           printf("Connect failed: %s\n", mysqli_connect_error());
           exit();
        } else {
          return $dbconn;
        }
    }
}//end dbClass

?>

<?php
class LoginClass extends DBController {
    // class 자식클래스 extends 부모클래스
    // override : 부모 클래스와 자식 클래스가 같은 메소드를 정의했을 경우 자식 클래스가 우선시된다.
    // AES 암호화
    function AES_encrypt($plain_text){
        global $secret_key, $secret_iv;
        $encrypt_method = "AES-256-CBC";
        $key = hash('sha256', $secret_key);
        $iv = substr(hash('sha256', $secret_iv), 0, 16);
        $output = openssl_encrypt($plain_text, $encrypt_method, $key, true, $iv);
        return base64_encode($output);
    }

    // AES 복호화
    function AES_decrypt($encrypted_string){
        global $secret_key, $secret_iv;
        $encrypt_method = "AES-256-CBC";
        $key = hash('sha256', $secret_key);
        $iv = substr(hash('sha256', $secret_iv), 0, 16);
        $output = openssl_decrypt(base64_decode($encrypted_string), $encrypt_method, $key, true, $iv);
        return $output;
    }

}//end class LoginClass
?>


https://gist.github.com/kijin/8404004 를 참조하여 AES 암호화, 복호화를 해도 좋을 거 같다.


'Web 프로그램 > 암호화 처리' 카테고리의 다른 글

phpMyAdmin 해킹시도 흔적  (0) 2018.06.11
[PHP] SHA384 패스워드 만들기  (0) 2017.01.27
[보안] PHP AES 암호화 예제  (0) 2016.10.16
[보안] SEED PHP 사용법  (0) 2016.10.15
블로그 이미지

Link2Me

,
728x90

Apache AccessLog 를 분석하다보니 이런 패턴이 보인다. (시도한 IP주소는 삭제했음)



[01/Jun/2018:06:46:41 +0900] "GET /phpmyadmin/index.php HTTP/1.1" 404 218
[01/Jun/2018:06:46:41 +0900] "GET /phpMyAdmin/index.php HTTP/1.1" 404 218
[01/Jun/2018:06:46:41 +0900] "GET /pmd/index.php HTTP/1.1" 404 211
[01/Jun/2018:06:46:41 +0900] "GET /pma/index.php HTTP/1.1" 200 1
[01/Jun/2018:06:46:43 +0900] "GET /pma/index.php HTTP/1.1" 200 1
[01/Jun/2018:06:46:43 +0900] "GET /PMA/index.php HTTP/1.1" 404 211
[01/Jun/2018:06:46:43 +0900] "GET /PMA2/index.php HTTP/1.1" 404 212
[01/Jun/2018:06:46:43 +0900] "GET /pmamy/index.php HTTP/1.1" 404 213
[01/Jun/2018:06:46:44 +0900] "GET /pmamy2/index.php HTTP/1.1" 404 214
[01/Jun/2018:06:46:44 +0900] "GET /mysql/index.php HTTP/1.1" 404 213
[01/Jun/2018:06:46:44 +0900] "GET /admin/index.php HTTP/1.1" 404 213
[01/Jun/2018:06:46:44 +0900] "GET /db/index.php HTTP/1.1" 404 210
[01/Jun/2018:06:46:44 +0900] "GET /dbadmin/index.php HTTP/1.1" 404 215
[01/Jun/2018:06:46:44 +0900] "GET /web/phpMyAdmin/index.php HTTP/1.1" 404 222
[01/Jun/2018:06:46:44 +0900] "GET /admin/pma/index.php HTTP/1.1" 404 217
[01/Jun/2018:06:46:44 +0900] "GET /admin/PMA/index.php HTTP/1.1" 404 217
[01/Jun/2018:06:46:44 +0900] "GET /admin/mysql/index.php HTTP/1.1" 404 219
[01/Jun/2018:06:46:44 +0900] "GET /admin/mysql2/index.php HTTP/1.1" 404 220
[01/Jun/2018:06:46:44 +0900] "GET /admin/phpmyadmin/index.php HTTP/1.1" 404 224
[01/Jun/2018:06:46:44 +0900] "GET /admin/phpMyAdmin/index.php HTTP/1.1" 404 224
[01/Jun/2018:06:46:44 +0900] "GET /admin/phpmyadmin2/index.php HTTP/1.1" 404 225
[01/Jun/2018:06:46:44 +0900] "GET /mysqladmin/index.php HTTP/1.1" 404 218
[01/Jun/2018:06:46:44 +0900] "GET /mysql-admin/index.php HTTP/1.1" 404 219
[01/Jun/2018:06:46:44 +0900] "GET /phpadmin/index.php HTTP/1.1" 404 216
[01/Jun/2018:06:46:44 +0900] "GET /phpmyadmin0/index.php HTTP/1.1" 404 219
[01/Jun/2018:06:46:44 +0900] "GET /phpmyadmin1/index.php HTTP/1.1" 404 219
[01/Jun/2018:06:46:44 +0900] "GET /phpmyadmin2/index.php HTTP/1.1" 404 219
[01/Jun/2018:06:46:44 +0900] "GET /myadmin/index.php HTTP/1.1" 404 215
[01/Jun/2018:06:46:44 +0900] "GET /myadmin2/index.php HTTP/1.1" 404 216
[01/Jun/2018:06:46:44 +0900] "GET /xampp/phpmyadmin/index.php HTTP/1.1" 404 224
[01/Jun/2018:06:46:44 +0900] "GET /phpMyadmin_bak/index.php HTTP/1.1" 404 222
[01/Jun/2018:06:46:44 +0900] "GET /www/phpMyAdmin/index.php HTTP/1.1" 404 222
[01/Jun/2018:06:46:44 +0900] "GET /tools/phpMyAdmin/index.php HTTP/1.1" 404 224
[01/Jun/2018:06:46:44 +0900] "GET /phpmyadmin-old/index.php HTTP/1.1" 404 222
[01/Jun/2018:06:46:44 +0900] "GET /phpMyAdminold/index.php HTTP/1.1" 404 221
[01/Jun/2018:06:46:44 +0900] "GET /phpMyAdmin.old/index.php HTTP/1.1" 404 222
[01/Jun/2018:06:46:44 +0900] "GET /pma-old/index.php HTTP/1.1" 404 215
[01/Jun/2018:06:46:44 +0900] "GET /claroline/phpMyAdmin/index.php HTTP/1.1" 404 228
[01/Jun/2018:06:46:44 +0900] "GET /typo3/phpmyadmin/index.php HTTP/1.1" 404 224
[01/Jun/2018:06:46:44 +0900] "GET /phpma/index.php HTTP/1.1" 404 213
[01/Jun/2018:06:46:44 +0900] "GET /phpmyadmin/phpmyadmin/index.php HTTP/1.1" 404 229
[01/Jun/2018:06:46:44 +0900] "GET /phpMyAdmin/phpMyAdmin/index.php HTTP/1.1" 404 229



404는 파일이 존재하지 않는다는 의미이고 200은 파일은 존재한다는 의미다.

phpMyAdmin 사용을 매우 주의해야겠다는 생각이 들었다.

특정한 IP에서만 접속 가능하도록 ipFiltering을 걸어두었기에 brute force 공격(무차별 root 패스워드 대입공격)은 불가능하다.

하지만 ipFiltering 을 걸어두지 않고 MySQL 패스워드를 간단하게 사용하는 사이트가 있다면 사이트가 털릴 가능성이 매우 높다.

이런 로그를 잘 살펴보지 않으면 무슨 문제가 발생하고 있는지 조차 모를 수 있다.

1. MySQL root 패스워드는 복잡하게 생성해야 한다.

2. 특정 IP 에서만 접속 허용하는 ipFiltering.php 를 만들어서 incluce_once 시켜서 접속 IP를 확인하게 만든다.


블로그 이미지

Link2Me

,
728x90

DB 암호를 강력하게 만들기 위해서 SHA384를 적용하는 코드를 작성해봤다.


<?php
$userpw = "admin1234"; // 사용자 입력 암호
function createSalt()
{
    $text = md5(uniqid(rand(), TRUE));
    return substr($text, 0, 34);
}

$salt = createSalt(); // 랜덤하게 생성
$password = hash('sha384', $userpw.$salt);
echo $salt.'<br />';
echo $password.'<br />';
echo strlen($password);
?>


DB 패스워드를 다른 키($salt)와 조합하여 저장하도록 하는 로직이다.

여기서 $salt 값이 계속 변하므로 이 키값도 같이 DB에 저장하지 않으면 다음번에 로그인할 때 문제가 생긴다.

따라서 테이블에 key 값을 저장하는 테이블도 하나 추가하는게 좋다.

블로그 이미지

Link2Me

,
728x90

AES 암호화 방식으로 암호화하는 예제이다.


1. AESCrypt Class 를 선언해준다. Class 명칭은 본인 스타일에 맞게 수정한다.


class AESCrypt {
    function encrypt($plain_text){
        global $key, $iv;
        // AES 암호화 기법은 평문을 128비트 단위로 나누어 암호화, 복호화를 수행
        // 각각의 128비트를 4x4 행렬로 표현하여 연산을 수행함
        // 사용하는 암호화 키의 길이는 128, 192, 256비트 중 하나를 선택할 수 있음
        // CBC(Cipher Block Chaining) Mode : 블록 암호화 운영 모드 중 보안 성이 제일 높은 암호화 방법으로 가장 많이 사용
        // 평문의 각 블록은 XOR연산을 통해 이전 암호문과 연산되고 첫번째 암호문에 대해서는 IV(Initial Vector)가 암호문 대신 사용
        // IV (initialization vector)는 제 2의 키가 될 수 있으며, 길이는 16bits
        $encryptedMessage = openssl_encrypt($plain_text, "aes-256-cbc", $key, true, $iv);
        return base64_encode($encryptedMessage);
    }

    function decrypt($base64_text){
        global $key, $iv;
        $decryptedMessage = openssl_decrypt(base64_decode($base64_text), "aes-256-cbc", $key, true, $iv);
        return $decryptedMessage;
    }

}//end class



2. AES 사용법

class.crypto.php 파일안에다 AESCrypt Class 를 선언했다.


<?php
    include 'phpclass/class.crypto.php';
    $crypto = new Crypto(); // 암호화 객체 생성
    $text ='암호화할 문장을 여기에 적어주시면 됩니다.';
    $enc = $crypto->encrypt($text);
    echo $enc.'<br /> 원문 길이 : '.strlen($text).'  암호화 길이 : '.strlen($enc).'<br />';
    $dec = $crypto->decrypt($enc);
    echo $dec.'<br /><br />';

    $aescrypt = new AESCrypt();
    $key = "key996rfy7ja6ng7gisu8kim55s";
    $iv = "f781576ae8dfe846";
    $enc = $aescrypt->encrypt($text);
    echo $enc.'<br /> 원문 길이 : '.strlen($text).'  암호화 길이 : '.strlen($enc).'<br />';
    $dec = $aescrypt->decrypt($enc);
    echo $dec;
   
?>


3. 결과

최대 길이는 SEED 와 AES 모두 입력되는 길이에 비례하여 길어진다.


SEED 결과

48cdef6c9738608cbbfb30965e1c665904a214ef99a0dc20ebf6cf6592de45aaf9eeb48106628db5b3747122251d16145cd9a0f17afc6857623891ff4882864e
원문 길이 : 59 암호화 길이 : 128
암호화할 문장을 여기에 적어주시면 됩니다.


AES 결과
lcFPY8OXrCHTUFNaz7PeQ+xzYMsxxw2SDFD1aR8nb3QNa7z6ELfxuhNjIVg/j/5tyWN13StkGwZoL0TARI9vwA==
원문 길이 : 59 암호화 길이 : 88
암호화할 문장을 여기에 적어주시면 됩니다.


4. 비고

테스트를 해보니 AES 암호화는 key 길이가 32비트까지 인식 하는 거 같다.





블로그 이미지

Link2Me

,
728x90

SEED PHP 파일은 http://seed.kisa.or.kr/iwt/ko/index.do 에 가면 있다.

KISA 사이트는 소스가 PHP 인지 JSP 인지 식별이 어렵게 do 라는 확장자를 사용했다는 걸 알 수 있다.


알림마당 -> 자료실에서 PHP 버전을 찾아서 다운로드 받을 수 있다.

http://seed.kisa.or.kr/iwt/ko/bbs/EgovReferenceList.do?bbsId=BBSMSTR_000000000002


   [암호화 및 복호화 과정]


SEED는 128비트의 암⋅복호화키를 이용하여 임의의 길이를 갖는 입력 메시지를 128비트의 블록단위로 처리하는 128비트 블록암호 알고리즘이다. 따라서 임의의 길이를 가지는 평문 메시지를 128비트씩 블록단위로 나누어 암호화하여 암호문을 생성한다.


예제를 실행해보니 복호화가 제대로 안된다.

이걸 일일이 분석해볼 시간도 없고 능력도 안되어서 바로 포기했다.


그리고 구글링해서 다른 걸 찾아냈다.

http://qnibus.com/blog/how-to-use-seed128-for-php/

https://github.com/qnibus/seed128/


class.seed.php 파일을 만든 분의 사이트에 가서 class.seed.php 파일 내용을 수정하라고 나온다.


필요한 파일 class.crypto.php, class.seed.php 2개를 폴더에 복사 및 수정해서 소스 디렉토리에 저장한다.


사용법

ㅇ class.crypto.php 파일 내에 있는 $pbUserKey 값은 수정해서 사용한다.

ㅇ $IV 값도 수정해서 사용한다.


<?php
    include 'phpclass/class.crypto.php';
    $crypto = new Crypto(); // 암호화 객체 생성
    $text ='암호화할 문장을 여기에 적어주시면 됩니다.';
    $enc = $crypto->encrypt($text);
    echo $enc.'<br /> 원문 길이 : '.strlen($text).'  암호화 길이 : '.strlen($enc).'<br />';
    $dec = $crypto->decrypt($enc);
    echo $dec;
?>


평문($text)의 길이가 길면 비례해서 암호문의 길이도 길어진다.

그러므로 DB column 설계시 고려해서 해야 한다.

개인정보인 전화번호를 암호화 저장하는게 안전할 거 같아서 테스트를 해보니 암호화시 32 bytes 가 된다.

DB에 암호화 저장하고 화면에 보여줄 때 복호화해서 보여주면 된다.


Android 와 연동해서 테스트는 아직 안해봤다.


블로그 이미지

Link2Me

,