웹 해킹/웹 개발

약한 문자열 강도 보안 패치

Almon 2025. 4. 7. 19:49

 1. 개요

 

약한 문자열 강도 취약점 이란?

약한 문자열 강도 취약점은 사용자가 비밀번호를 단순하거나 예측 가능한 형태로 설정할 수 있는 취약점을 말합니다. 예를 들어 password123!, admin1234, 또는 아이디, 전화번호와 같이 추측하기 쉬운 정보를 이용한 비밀번호 등은 공격자에게 쉽게 노출될 수 있습니다.

이러한 취약점은 사전 대입 공격이나 무차별 대입 공격에 취약합니다. 공격자는 자동화된 스크립트를 사용하여 짧은 시간 내에 비밀번호를 추측할 수 있으며, 사용자 계정에 대한 인증 우회가 가능해집니다.

계정에 접근한 공격자는 민감한 정보를 탈취하거나 권한을 악용할 수 있습니다. 따라서 문자열 강도를 강화하고 보안 정책을 통해 강제하는 것은 웹 애플리케이션의 보안을 유지하는 데 있어 매우 중요합니다.

 

보안 패치의 목적 및 중요성

공격자가 추측 가능한 비밀번호(Password123!, admin1234 등)를 이용해 계정을 생성한 경우, 자동화된 스크립트를 이용하여 사전 대입 공격, 무차별 대입 공격을 통해 계정을 탈취할 수 있습니다. 이를 통해 공격자는 해당 계정에 접근해  민감한 정보를 탈취하거나, 권한을 악용할 수 있습니다. 따라서 약한 문자열 강도 취약점에 대한 보안 패치는 다음과 같은 목적을 가집니다.

 

1. 사용자가 추측 가능한 비밀번호 설정하지 못하도록 차단합니다.

2. 보안 정책(비밀번호 복잡성 정책)을 통해 강도 높은 비밀번호 사용을 강제합니다.

 

 2. 취약점 분석

 

취약점 발생 원인

회원가입 및 비밀번호 수정 시 비밀번호 강도를 검사하는 로직이 없어 공격자가 추측하기 쉬운 취약한 비밀번호를 설정할 수 있습니다.

 

sign_up_proc.php

<?php 
....
    $pass = $_POST['pass'];
    $passCheck = $_POST['passCheck'];
....        
    if (!$id_duple && !$pass_duple && !$nick_duple) {
        $result = true;
        $pass = password_hash($pass, PASSWORD_ARGON2ID);
        $name = htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
        $id = htmlspecialchars($id, ENT_QUOTES, 'UTF-8');
        $nick = htmlspecialchars($nick, ENT_QUOTES, 'UTF-8');
        // 비밀번호 강도 검사 없이 SQL 쿼리에 삽입
        runSQL("insert into users (name, user_id, nickname, email, password, login) values ('$name', '$id', '$nick', '$email', '$pass', '0')");
    }
....

 

mypage_update_proc.php

....
        $password = $_POST['password'] ?? null;
        $password_filtered = preg_replace("/\s+/", "", $password);
        
        // 비밀번호 공백 검사
        if($password != null && $password === $password_filtered) {
            $pass_hash = password_hash($password, PASSWORD_ARGON2ID);
            // 비밀번호 강도 검사 없이 SQL 쿼리에 삽입
            $sql = $sql . ", password='$pass_hash'";
            $pass_result = true;
        }
....   
        $sql = $sql . " where user_id='$user_id'";
        // SQL 쿼리 실행
        $result = runSQL($sql);

 

취약점 예시

취약한 비밀번호 설정이 가능하여 무차별 대입 공격으로 쉽게 사용자 계정 탈취가 가능합니다.

 

1. 회원가입 페이지에 접속합니다.

 

2. 취약한 비밀번호를 설정하고 회원가입 합니다.

 

3. Burp Suite의 Intruder 기능을 이용해 111부터 130까지의 숫자 범위를 대상으로 하는 무차별 대입 공격을 설정합니다.

 

4. Payload의 값이 123일 때 응답의 길이가 다른 응답보다 길게 나타납니다. 응답 내용을 확인한 결과 Set-Cookie 헤더가 포함되어 있어 로그인에 성공한 것을 확인할 수 있습니다.

 

 3. 보안 패치 적용

 

보안 조치 방법

사용자가 약한 강도의 비밀번호를 설정하지 못하도록 아래와 같은 비밀번호 정책을 적용합니다.

 

1. 비밀번호는 영어 대문자, 소문자, 숫자, 특수문자 중 최소 2종류 이상을 조합해야 합니다.

2. 비밀번호의 최소 길이는 10자리 이상이어야 합니다.

 

수정 코드

회원가입, 비밀번호 수정 시 정규식을 이용해 비밀번호 강도를 검사하는 로직을 추가하였습니다.

 

check_password_strong.php 추가

<?php
function check_password_strong($password) {
    if (strlen($password) < 10) {
        return false;
    }

    $patterns = ['/[A-Z]/', '/[a-z]/', '/[0-9]/', '/[!"#$%&\'()*+,\-\.\/:;<=>?@\[₩\]^_`{|}~]/'];

    $types = 0;

    foreach ($patterns as $pattern) {
        if (preg_match($pattern, $password)) {
            $types++;
            if ($types >= 2) {
                return true;
            }
        }
    }

    return false;
}

 

sign_up_proc.php

<?php 
....
    $pass = $_POST['pass'];
    $passCheck = $_POST['passCheck'];
    $pass_strong = false;
....        
    // 비밀번호 강도 검사
    $pass_strong = check_password_strong($pass);
    if (!$id_duple && !$pass_duple && !$nick_duple && $pass_strong) {
        $result = true;
        $pass = password_hash($pass, PASSWORD_ARGON2ID);
        $name = htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
        $id = htmlspecialchars($id, ENT_QUOTES, 'UTF-8');
        $nick = htmlspecialchars($nick, ENT_QUOTES, 'UTF-8');
        
        runSQL("insert into users (name, user_id, nickname, email, password, login) values ('$name', '$id', '$nick', '$email', '$pass', '0')");
    }
....

 

mypage_update_proc.php

....
        $password = $_POST['password'] ?? null;
        $password_filtered = preg_replace("/\s+/", "", $password);
        
        if($password != null && $password === $password_filtered) {
            // 비밀번호 강도 검사
            if (check_password_strong($password)) {
                $pass_hash = password_hash($password, PASSWORD_ARGON2ID);
                $sql = $sql . ", password='$pass_hash'";
                $pass_result = true;
            }
        }
....   
        $sql = $sql . " where user_id='$user_id'";
        // SQL 쿼리 실행
        $result = runSQL($sql);

 

 4. 보안 패치 결과

 

보안 패치 후 테스트

보안 정책 적용 후, 단순하거나 예측 가능한 비밀번호로는 회원가입 및 비밀번호 변경이 불가능하며, 비밀번호 강도 정책에 부합하는 경우에만 정상적으로 동작하는 것을 확인했습니다.

 

1. 약한 문자열로 비밀번호를 설정 한 뒤 회원가입을 시도합니다.

 

2. 회원가입에 실패합니다.

 

3. 보안 정책에 맞는 비밀번호를 설정한 뒤 회원가입을 시도합니다.

 

4. 회원가입에 성공합니다.