[시큐어코딩 가이드] 2-2-5. 암호화되지 않은 중요정보

암호화되지 않은 중요정보

정의

  • 많은 응용 프로그램은 메모리나 디스크 상에서 중요한 정보(개인정보, 인증정보, 금융정보 등)를 처리하는데, 이러한 정보가 제대로 보호되지 않을 경우, 보안 문제가 발생하거나 데이터의 무결성이 깨질 수 있다.
  • 사용자 또는 시스템의 중요 정보가 포함된 데이터를 평문으로 송·수 또는 저장 시 인가되지 않은 사용자에게 민감한 정보가 노출될 수 있다.

 

안전한 코딩기법

  • 중요정보(개인정보, 금융정보, 패스워드)를 저장하거나 통신채널로 전송할 때는 반드시 암호화 과정을 거쳐야 하며, 중요정보를 읽거나 쓸 경우에 권한인증 등을 통해 적합한 사용자만 중요정보에 접근하도록 해야 한다.
  • 가능하다면 SSL 또는 HTTPS 등과 같은 보안 채널을 사용해야 한다.

 

코드예제

중요정보 평문저장

다음은 안전하지 않은 코드예제로, 사용자로부터 전달받은 패스워드 암호화를 누락한 코드입니다.

#암호화되지 않은 중요정보(안전X)
def update_pass_bad(dbconn, password, user_id):
    c = dbconn.cursor()
    c.execute('UPDATE USERS SET PASSWORD=%s WHERE USER_ID=%s', password, user_id)
    dbconn.commit()

 

다음은 안전한 코드예제로, 해시 알고리즘을 이용하여 단방향 암호화 이후에 패스워드를 저장하는 코드입니다.

#암호화되지 않은 중요정보(안전O)
def update_pass_good(dbconn, password, user_id, salt):
    hash_obj = SHA256.new()
    hash_obj.update(bytes(password + salt, 'utf-8'))
    hash_pwd = hash_obj.hexdlgest()

    c = dbconn.cursor()
    c.execute('UPDATE USERS SET PASSWORD=%s WHERE USER_ID=%s', (hash_pwd, user_id))
    dbconn.commit()

 

중요정보 평문전송

다음은 안전하지 않은 코드예제로, 인자값으로 전달받은 패스워드를 검증 없이 네트워크를 통해 전송하는 코드입니다. 이런 경우 패킷 스니핑을 통하여 패스워드가 노출될 수 있습니다.

#암호화되지 않은 중요정보(안전X)
HOST = '127.0.0.1'
PORT = 65434

def send_password_bad(password):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((HOST, PORT))
        s.sendall(password.endcode('utf-8'))
        data = s.recv(1024)

 

다음은 안전한 코드예제로, 네트워크를 통해 전달되는 패스워드가 노출되지 않도록 암호화하여 전송하는 코드입니다.

#암호화되지 않은 중요정보(안전O)
HOST = '127.0.0.1'
PORT = 65434

def send_password_good(password):
    block_key = os.environ.get('BLOCK_KEY')
    aes = AEScipher(block_key)
    enc_passowrd = aes.encrypt(password)

    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.connect((HOST, PORT))
        s.sendall(enc_passowrd.endcode('utf-8'))
        data = s.recv(1024)

class AEScipher:
    BS = AES.block_size
    def __init__(self, s_key):
        self.s_key = hashlib.sha256(s_key.endcode('utf-8')).digest()
    def pad(self, m):
        return m + bytes([self.BS - len(m) % self.BS] * (self.BS - len(m) % self.BS))
    def encrypt(self, plain):
        plain = self.pad(plain.encode())
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.s_key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(plain)).decode('utf-8')

 

 

 

 

보안기능/암호화되지 않은 중요정보

[참고문헌] Python 시큐어코딩 가이드(2022) / KISA(한국인터넷진흥원)