OWASP Top 10

양동귀·2024년 10월 12일

OWASP Top 10

OWASP Top Ten은 웹 애플리케이션에서 가장 위험한 보안 취약점 10가지를 정리한 목록입니다.
전 세계 보안 전문가들이 제공한 데이터를 바탕으로 만들어지며, 매 몇 년마다 업데이트되어 최신 보안 위협을 반영해 목록을 갱신 합니다.

1. Broken Access Control

사용자가 허용되지 않는 기능이나 데이터에 접근하여 발생하는 보안 취약점 입니다.

예시

  • /admin 경로로 관리자 메뉴로 접근
  • ID 123인 유저가 url 상의 파라미터인 userID를 userID=567로 보냄

해결방법

  • 역할 기반 접근 제어 (RBAC)
    사용자의 역할에 맞게 명확한 권한에 대한 정의를 하여, 자기의 역할에 필요한 리소스와 기능에만 접근 가능하도록 해야합니다.
  • 최소 권한 원칙
    사용자가 서비스를 사용하는데 필요한 최소한의 권한을 부여해야 합니다. (사용자의 최소 권한)
    (RBAC 역할에 대해 최소 권한)
  • 간접 참조 (Indirect Object References)
    매핑이나 토큰을 사용하여 직접적인 숫자나 데이터 참조를 피하는 방식을 사용

2.암호화 실패 (Cryptographic Failures)

암호화가 필요한 민감한 데이터를 암호화 하지않았을때 발생하는 보안 취약점 입니다.

예시

  • 비밀번호 등과 같은 민감한 데이터 정보를 암호화 되지 않은 평문으로 저장
  • 오래된 암호화 알고리즘을 사용
  • 데이터를 탈취, 변조

해결 방법

  • SSL/TLS 인증서 관리:
    SSL/TLS 인증서는 항상 유효한 상태를 유지해야 하며, TLS를 사용해 네트워크를 통한 데이터 전송을 암호화해야 중간자 공격(MITM)을 예방할 수 있습니다.
  • 강력한 암호화 알고리즘 (AES-256) 사용
  • 민감한 정보의 저장은 해시 알고리즘(bcrypt, scrypt, Argon2)을 사용하여 저장
  • 암호화 키 관리
    • 암호화 키는 소스 코드에 저장 되면 안됩니다
    • 생성 시 임의성(Randomness)을 보장하는 보안된 난수 생성기를 사용해야 합니다.
    • 키 관리 시스템(KMS, Key Management System)을 사용합니다 (AWS KMS, Google Cloud KMS)
    • 정기적인 암호화 키 교체
    • 사용자히 않는 암호화 키는 재생하여 사용될 수 없도록 처리후 폐기
    • 암호화 키 접근, 사용기록을 로그로 남김, 모니터링

3.인젝션 (Injection)

외부로부터 입력받은 데이터를 제대로 검증하지 않고, 해당 데이터를 데이터베이스 쿼리나 운영체제 명령 등으로 실행하는 경우 발생하는 보안 취약점 입니다.
대표적으로 sql Injection이 있습니다.

예시

  • sql Injection
    passord 부분에 무조건 참이 되게 하는 조건을 추가하여 비밀번호를 입력하지 않아도 로그인 되게 해버림
SELECT * FROM users WHERE username = 'admin' AND password = '' OR '1'='1';

해결방법

  • 사용자 입력 데이터의 필터링 (Sanitization)
    입력 받은 데이터가 사전에 설정한 데이터의 형태가 맞는지 확인
  • 매개변수화된 쿼리(Parameterized Queries)
    쿼리와 입력 데이터를 분리 하여, 입력 자체는 쿼리를 완성하기 위한 데이터로만 취급
  • 입력 유효성 검사(Input Validation)
    사전에 설정한 데이터 구조인지, 쿼리의 매개변수에 넣을때 문제 없는 데이터 인지(특수문자) 유효성 검사

4.불완전한 설계 (Insecure Design)

보안적인 관점에서 적절하게 설계되지 않았을 때 발생하는 보안 취약점 입니다.
보안 요구 사항을 충분히 고려하지 않았거나, 위험 관리가 부족할 때 발생합니다.

원인

  • 세션 관리 미흡, 세션 하이재킹(토큰 탈취)과 같은 공격에 노출
  • 오류 처리 및 로깅 부족
  • 데이터 보호 미흡, 데이터 암호화를 설계 단계에서 충분히 고려하지 않으면, 데이터 유출의 위험
  • 불필요하게 복잡한 기능 추가, 핵심 기능에 필수적이지 않거나 복잡한 기능을 추가하면 공격 표면이 넓어져 공격에 취약
  • 위협 모델링 부족: 잠재적인 보안 위협을 미리 분석하고 설계에 반영하지 않는 것
  • 테스트 부족: 개발 과정에서 보안 테스트를 충분히 포함하지 않으면, 취약점 사전 예방 어려움

해결 방안

  • 잠재적 위협을 설계 단계에서 분석하고, 그에 맞는 방어 전략을 수립
  • 데이터 입력 검증 설계 단계에 포함
  • 세션 하이재킹을 방지하기 위한 보안 강화 설계(세션 타임아웃 설정, 안전한 쿠키 사용 등)를 적용
  • 에러 메시지나 로그에 중요한 정보가 노출되지 않도록 설계
  • 데이터 암호화, 데이터 보호 메커니즘을 고려

5. 보안 설정 오류 (Security Misconfiguration)

시스템의 보안 설정이 잘못 정의되었거나, 제대로 구현되지 않거나 유지 관리되지 않을 때 발생하는보안 취약점 입니다. 이 취약점은 애플리케이션 스택의 어느 수준에서도 발생할 수 있습니다.

원인

  • 기본 사용자명 및 비밀번호 사용: 설정 후 기본 계정 정보를 변경하지 않으면, 공격자는 쉽게 시스템에 접근 (root / 1)
  • 불완전한 설정: 필요한 모든 보안 제어가 제대로 구현되지 않아 시스템의 일부가 보호되지 않은 상태로 남아 있을 수 있음
  • 디버깅 정보 노출: 프로덕션 환경에 디버깅 정보를 남겨두면, 공격자가 이를 악용해 시스템에 대한 중요한 정보를 파악 가능
  • 보안 패치 미적용: 시스템에 최신 보안 패치가 적용되지 않으면, 알려진 취약점에 쉽게 노출
  • 디렉터리 목록 노출: 디렉터리 목록이 허용된 경우, 공격자는 시스템의 구조와 중요한 파일을 쉽게 탐색

해결방법

  • 기본 사용자 이름과 비밀번호는 반드시 변경, 자격 증명을 설정
  • 보안 패치 및 업데이트 주기적 적용
  • 필요하지 않은 기능을 비활성화, 미설치, 삭제
  • 에러 처리시 민감한 정보가 노출되지 않도록 설정
  • 최소 권한 원칙 적용

6. 취약하고 오래된 구성 요소(Vulnerable and Outdated Components)

최신 보안 패치가 적용되지 않은 오래된 소프트웨어를 사용하는 경우 발생하는 보안 취약점 입니다.

원인

  • 오래된 프레임워크나 라이브러리는 새로운 보안 취약점이 발견되어도 더 이상 업데이트되지 않기 때문에 공격자가 이를 악용해 시스템에 침투
  • 패치되지 않은 플러그인이나 확장 기능은 시스템 내의 민감한 데이터에 접근할 수 있는 취약점을 제공할 수 있으며, 공격자에게 쉬운 진입점을 제공

해결방법

  • 구성 요소의 정기적인 보안 검사: 취약한 구성 요소를 식별하고, 이를 자동으로 모니터링하는 도구를 사용 (Reflectiz 외부 의존성을 스캔하고, 취약점을 발견하면 경고를 제공)
  • 외부 구성 요소가 최신 상태로 유지되도록 정기적으로 업데이트하고 보안 패치를 적용
  • 지원 중단된 소프트웨어 교체 안전한 대체 솔루션으로 전환

7.식별 및 인증 실패 (Identification and Authentication Failures)

사용자의 신원을 확인하고 인증하는 과정에서 발생하는 취약점입니다. 사용자가 올바르게 인증되지 않거나, 인증 정보가 안전하지 않게 관리될 때 발생하며, 공격자는 이를 통해 시스템에 무단 접근할 수 있습니다.

원인

  • 약한 비밀번호 정책, 비밀번호가 너무 짧거나 복잡하지 않으면, 공격자가 이를 쉽게 추측

  • 다중 인증 미사용, 2단계 인증 같은 추가적인 보안 레이어가 없는 경우

  • 비밀번호 저장의 불안정성, 비밀번호를 평문으로 저장, 안전하지 않은 해시 알고리즘을 사용

  • 세션 관리 취약점, 세션이 만료되지 않거나, 세션 토큰이 쉽게 예측 가능한 경우

  • 무작위 대입 공격(Brute-force attacks): 공격자가 모든 가능한 비밀번호 조합을 시도해 인증 시스템을 뚫으려는 공격입니다. 약한 비밀번호를 사용할 경우 쉽게 성공할 수 있습니다.

  • 크리덴셜 스터핑(Credential Stuffing) 공격, 이는 유출된 사용자 이름과 비밀번호 목록을 사용해 다른 사이트에 무단 로그인을 시도하는 방식입니다.

해결방법

  • 강력한 비밀번호 정책 적용, 복잡한 비밀번호를 요구하고, 주기적인 변경을 권장
  • 다중 인증(2FA) 적용, 비밀번호 외에도 추가 인증 수단(예: SMS, OTP, 인증 앱)을 사용
  • 안전한 비밀번호 저장 방식 사용: 비밀번호는 bcrypt나 Argon2 같은 강력한 해시 알고리즘으로 저장하고, 솔트 값을 사용해 안전성을 높여야 합니다.
  • 세션 관리 강화, 만료시간 설정
  • 여러 번의 실패한 인증 시도를 감지해 계정을 잠그고, 사용자에게 경고

8.소프트웨어 데이터 무결성 실패 (Software and Data Integrity Failures)

소프트웨어나 데이터가 안전하게 보호되지 못하고, 공격자가 이를 수정하거나 변조할 수 있는 취약점입니다. 이 문제는 종종 업데이트, 데이터 처리, 코드 배포, 그리고 의존성 관리에서 발생합니다.

원인

  • 신뢰할 수 없는 업데이트 소스(서드파티 소프트웨어나 라이브러리)를 통해 소프트웨어가 변경될 때, 공격자가 악성 코드를 삽입
  • 무결성 검사 미사용, 소프트웨어나 데이터가 변경되었는지 확인하는 절차(디지털 서명, 해시 값 검사)가 없으면, 공격자는 중간에 데이터를 조작, 악성 코드 삽입
  • 비정상적인 데이터 입력 처리, 사용자로부터 입력된 데이터가 제대로 검증되지 않으면 공격자가 그 데이터를 조작해 소프트웨어나 시스템 손상시킴

해결방법

  • 소프트웨어 업데이트나 설치 시 신뢰할 수 있는 출처에서만 제공된 소프트웨어인지 확인하는 검증 절차를 적용
  • 코드 서명 사용, 코드 서명을 통해 소프트웨어의 진위 여부를 확인하고, 무단 변경 여부를 방지
  • 소프트웨어 및 데이터의 무결성을 정기적으로 감사하고 모니터링하여 이상이 발견되면 즉시 대응
  • 데이터 입력 검증, 모든 데이터 입력에 대해 엄격한 검증 절차를 적용

9.보안 로깅 및 모니터링 실패 (Security Logging and Monitoring Failures)

시스템 내에서 발생하는 보안 관련 이벤트들을 제대로 기록하지 않거나, 기록된 로그를 효과적으로 모니터링하지 않아 발생하는 취약점입니다.

원인

  • 불충분한 로그 기록, 시스템에서 발생하는 주요 보안 사건들이 기록되지 않으면, 사고 발생 시 원인을 파악하거나 대응하기가 어려움
  • 중앙 집중식 로그 관리 부족, 다양한 시스템의 로그가 분산되어 있으면 관리가 힘들어지고, 전체 보안 상황을 모니터링하기 어려움
  • 의심스러운 활동 모니터링 실패, 로그 모니터링을 하지 않으면 비정상적인 활동이나 공격 시도를 즉시 탐지 불가능

해결방법

  • 모든 중요한 사건 로그 기록, 사용자 인증 실패, 권한 상승 시도, 시스템 변경 등의 보안 사건을 기록
  • 중앙 집중식 로그 관리 (모든 로그를 한 곳에서 관리)
  • 로그 데이터를 정기적으로 검토
  • 알림 및 경고 시스템 설정, 비정상적인 활동이 탐지되면 즉시 경고를 받도록 설정

10. Server-Side Request Forgery (SSRF)

공격자가 서버를 속여서 서버 측에서 임의의 요청을 보내도록 만드는 취약점입니다. 이 공격은 서버가 신뢰할 수 있는 클라이언트의 요청을 처리하는 동안 발생할 수 있으며, 공격자가 외부 시스템이나 내부 네트워크 리소스에 접근할 수 있게 됩니다.

원인

  • 사용자가 제공한 URL을 기반으로 서버가 외부 리소스에 요청을 보낼 때, URL에 대한 제한이나 검증이 없으면 공격자가 악의적인 URL을 입력하여 서버가 원치 않는 요청을 하도록 유도
  • 공격자는 내부 시스템, API, 데이터베이스 등 보호된 리소스에 접근하여 민감한 데이터를 수집하거나 서버 환경을 조작

해결방법

  • 사용자가 입력한 URL 검증, 화이트리스트에 등록된 URL만 허용
  • 서버가 내부 시스템에 접근할 수 있는 권한을 최소한으로 제한
  • 민감한 서비스를 보호하기 위해 네트워크를 분할
  • 서버가 요청을 보낼 수 있는 서비스 및 프로토콜을 제한

해결 방안 예시 코드

1. 역할 기반 접근 제어(RBAC)

const express = require('express');
const app = express();

// 역할 미들웨어 작성
function authorize(roles) {
  return (req, res, next) => {
    if (!req.user || !roles.includes(req.user.role)) {
      return res.status(403).send('접근이 거부되었습니다.');
    }
    next();
  };
}

app.get('/admin', authorize(['admin']), (req, res) => {
  res.send('관리자 페이지');
});

2. 안전한 비밀번호 해싱

  • bcrypt을 사용
const bcrypt = require('bcrypt');

async function hashPassword(plainPassword) {
  const saltRounds = 10;
  const hash = await bcrypt.hash(plainPassword, saltRounds);
  return hash;
}

3. 매개변수화된 쿼리 사용

const mysql = require('mysql');
const connection = mysql.createConnection({ /* DB 설정 */ });

const username = req.body.username;
const password = req.body.password;
// todo: 입력 검증

connection.query('SELECT * FROM users WHERE username = ? AND password = ?', [username, password], (error, results) => {
  if (error) throw error;
  // 결과 처리
});

4. 입력 검증 추가

  • 정규식 활용, 입력 문자 제한
//입력 검증
function validateInput(data) {
  // 정규식 이용, 알파벳과 숫자만 허용
  const validDataPattern = /^[a-zA-Z0-9]*$/; 
  return validDataPattern.test(data);
}

app.post('/submit', (req, res) => {
  const userInput = req.body.input;
  if (!validateInput(userInput)) {
    return res.status(400).send('유효하지 않은 입력입니다.');
  }
  // 데이터 처리
});

5. 보안 패치 관리

  • spring security
// Spring Security 설정
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable() // CSRF 보호 비활성화
        .authorizeRequests()
        .antMatchers("/admin").hasRole("ADMIN")
        .anyRequest().authenticated();
  }
}

6. 다중 인증(2FA) 추가

  • 2차 인증 키, speakeasy 라이브러리 활용
const speakeasy = require('speakeasy');

// 사용자에게 2FA 비밀 키 제공
const secret = speakeasy.generateSecret({ length: 20 });
console.log(secret.base32); // 사용자가 입력할 비밀 키

// 인증 시도
const userToken = req.body.token;
const verified = speakeasy.totp.verify({
  secret: secret.base32,
  encoding: 'base32',
  token: userToken
});
if (!verified) {
  return res.status(403).send('인증 실패');
}

7. 로그 기록 및 관리

  • winston logger 라이브러리 사용, 로그 기록을 외부 파일로 저장한다
const winston = require('winston');

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.Console()
  ]
});

// 특정 사건 로깅
logger.info('사용자 인증 실패', { userId: req.body.userId });

8. 사용자 입력 URL 검증

  • 허용된 url 관리
const allowedUrls = ['https://example.com/api', 'https://anotherexample.com/api'];

function isValidUrl(url) {
  return allowedUrls.includes(url);
}

app.post('/fetch-data', (req, res) => {
  const userUrl = req.body.url;
  if (!isValidUrl(userUrl)) {
    return res.status(400).send('허용되지 않는 URL입니다.');
  }
  // 요청 수행
});

참고
https://www.reflectiz.com/blog/owasp-top-ten-2024/
SSL/TLS : https://howhttps.works/ko/https-ssl-tls-differences/
세션 하이재킹 : https://www.kaspersky.co.kr/resource-center/definitions/what-is-session-hijacking
크리덴셜 스터핑 : https://www.akamai.com/ko/glossary/what-is-credential-stuffing

0개의 댓글