Skip to content

Commit 1b52336

Browse files
committed
docs: SC(5-3)
1 parent 7002222 commit 1b52336

File tree

13 files changed

+451
-19
lines changed

13 files changed

+451
-19
lines changed

_posts/2025-09-24-SC(4-3).md

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
---
2+
title: "[Security] Secure Coding(4-3) - 정규식 활용(입력값 필터링)"
3+
4+
categories: [Security, Secure Coding]
5+
tags:
6+
- [Security, Cyberattacks, 보안, 시큐어 코딩, 정규식, 필터링]
7+
toc: true
8+
toc_sticky: true
9+
10+
date: 2025-09-24
11+
last_modified_at: 2025-09-24
12+
---
13+
>🔒 시큐어 코딩 수업 정리
14+
15+
## 입력값 필터 만들기
16+
📚**<span style="color: #008000">필터(filter)</span>**: **클라이언트의 HTTP 요청과 응답을 가로채어 특정 작업을 수행**하는 서블릿 기반 컴포넌트
17+
18+
* 웹 애플리케이션에서 보안, 로깅, 데이터 변환등의 작업을 수행할 때 사용
19+
20+
**주요 역할**:
21+
* 요청/응답 로깅
22+
* 인증(Authentication) & 권한 검사(Authorization)
23+
* CORS 처리(다른 도메인의 요청 허용 또는 차단)
24+
* 데이터 검증 & 변환(요청 데이터 가공 및 유효성 검사)
25+
* 응답변환(JSON,XML 등 특정형식으로 변경)
26+
* 보안강화(SQL Injection, XSS 등의 공격 방어)
27+
28+
![alt text](../assets/img/CyberSecurity/springfilter.png)
29+
> Spring Boot Filter 구조
30+
31+
---
32+
33+
### 필터 구현 방법
34+
35+
#### **1. 기본 필터 클래스 구현**
36+
37+
```java
38+
public class CustomFilter implements Filter {
39+
40+
@Override
41+
public void init(FilterConfig filterConfig) throws ServletException {
42+
// 필터 초기화 (서버 시작 시 1회 실행)
43+
}
44+
45+
@Override
46+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
47+
throws IOException, ServletException {
48+
49+
HttpServletRequest httpRequest = (HttpServletRequest) request;
50+
System.out.println("Request URI: " + httpRequest.getRequestURI());
51+
52+
// 다음 필터 또는 컨트롤러로 진행
53+
chain.doFilter(request, response);
54+
}
55+
56+
@Override
57+
public void destroy() {
58+
// 필터 종료 (서버 종료 시 1회 실행)
59+
}
60+
}
61+
```
62+
63+
* `init()`: 필터가 생성될 때 딱 한 번 실행 (초기화 작업)
64+
* `doFilter()`: 요청이 올 때마다 실행되는 핵심 로직
65+
* `destroy()`: 필터가 제거될 때 실행 (정리 작업)
66+
* `chain.doFilter()`: 매우 중요! 다음 단계로 넘어가는 명령
67+
68+
#### **2. 필터를 Spring Boot에 등록**
69+
* **(방법 1)** `@Component` 어노테이션 사용 - 자동 등록
70+
71+
```java
72+
@Component
73+
public class CustomFilter implements Filter {
74+
75+
@Override
76+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
77+
throws IOException, ServletException {
78+
79+
HttpServletRequest httpRequest = (HttpServletRequest) request;
80+
System.out.println("Request Method: " + httpRequest.getMethod());
81+
82+
chain.doFilter(request, response);
83+
}
84+
}
85+
```
86+
87+
* 장점: 코드가 간단함
88+
* 단점: 필터 순서 지정 불가, URL 패턴 세밀하게 설정 불가
89+
90+
* **(방법 2)** `FilterRegistrationBean` 사용하여 수동 등록(우선순위 지정이 필요한 경우)
91+
92+
```java
93+
@Configuration
94+
public class FilterConfig {
95+
96+
@Bean
97+
public FilterRegistrationBean<CustomFilter> loggingFilter() {
98+
FilterRegistrationBean<CustomFilter> registrationBean = new FilterRegistrationBean<>();
99+
registrationBean.setFilter(new CustomFilter());
100+
registrationBean.addUrlPatterns("/api/*"); // 특정 URL 패턴에만 적용
101+
registrationBean.setOrder(1); // 필터 실행 순서 지정 (낮을수록 먼저 실행)
102+
return registrationBean;
103+
}
104+
}
105+
```
106+
107+
* 장점: 필터 실행 순서 제어 가능, URL 패턴 세밀하게 설정 가능, 여러 필터 관리 용이
108+
109+
#### Spring Security와 기본 필터
110+
111+
```java
112+
@Configuration
113+
public class DefaultSecurityConfig {
114+
115+
@Bean
116+
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
117+
http
118+
.authorizeHttpRequests(auth -> auth
119+
.anyRequest().authenticated() // 모든 요청은 인증 필요
120+
)
121+
.formLogin() // 기본 로그인 폼 활성화
122+
.httpBasic(); // HTTP Basic 인증 활성화
123+
124+
return http.build();
125+
}
126+
}
127+
```
128+
129+
1. `.authorizeHttpRequests()`: 어떤 요청에 인증이 필요한지 설정
130+
2. `.formLogin()`: 로그인 페이지 자동 생성
131+
3. `.httpBasic()`: HTTP Basic 인증 방식 사용
132+
133+
---
134+
135+
### XSS 공격
136+
📚**<span style="color: #008000">XSS (Cross-Site Scripting)</span>**: 게시판처럼 입력 내용 그대로 표출되는 곳에 악성 스크립트를 넣어, 서비스 이용자의 브라우저에서 실행되도록 하는 공격
137+
138+
💡**예시**:
139+
* 게시판에 글을 쓸 때:
140+
* 공격자: <script>alert('해킹!');</script> 라고 입력
141+
* 결과: 게시글을 보는 모든 사람의 브라우저에서 경고창이 뜸! 😱
142+
143+
```
144+
실제 피해 사례:
145+
❌ 쿠키/세션 탈취 → 계정 도용
146+
❌ 사용자 정보 수집
147+
❌ 악성 사이트로 리다이렉트
148+
❌ 키로깅 (입력 내용 훔치기)
149+
❌ 가짜 로그인 페이지 표시
150+
```
151+
152+
* **🛡️ XSS 방어 전략**
153+
* 사용자 입력값에서 위험한 패턴의 문자열을 필터링
154+
* SpringBoot의 ServletFilter와 HttpServletRequestWrapper를 이용하여 모든 요청의 입력값을 가로챔
155+
* 입력값의 내용을 정규식으로 패턴을 확인하여 필터링 처리
156+
157+
![alt text](../assets/img/CyberSecurity/defendXSS.png)
158+
159+
#### XSS 필터 구현
160+
1. **XSSFilter 만들기**
161+
162+
```java
163+
@Component
164+
public class p043_XSSFilter implements Filter {
165+
166+
@Override
167+
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
168+
throws IOException, ServletException {
169+
170+
// 1. 일반 Request를 HttpServletRequest로 변환
171+
HttpServletRequest httpRequest = (HttpServletRequest) request;
172+
173+
// 2. 🔑 핵심: Request를 XSSRequestWrapper로 감싸기
174+
chain.doFilter(new p043_XSSRequestWrapper(httpRequest), response);
175+
176+
// 이제 Controller에서 받는 모든 파라미터는
177+
// XSSRequestWrapper를 거쳐서 자동으로 필터링됨
178+
}
179+
}
180+
```
181+
182+
2. **XSSRequestWrapper 만들기**
183+
184+
```java
185+
public class p043_XSSRequestWrapper extends HttpServletRequestWrapper {
186+
187+
public p043_XSSRequestWrapper(HttpServletRequest request) {
188+
super(request);
189+
}
190+
191+
// 1. 단일 파라미터 가져올 때
192+
@Override
193+
public String getParameter(String name) {
194+
String value = super.getParameter(name);
195+
return (value != null) ? sanitize(value) : null;
196+
}
197+
198+
// 2. 여러 파라미터 값 가져올 때 (checkbox 등)
199+
@Override
200+
public String[] getParameterValues(String name) {
201+
String[] values = super.getParameterValues(name);
202+
if (values != null){
203+
// 배열의 모든 값을 sanitize 처리
204+
for (int i = 0; i < values.length; i++) {
205+
values[i] = sanitize(values[i]);
206+
}
207+
}
208+
return values;
209+
}
210+
211+
// 3. 핵심 메서드: 위험한 문자열 제거
212+
private String sanitize(String input) {
213+
if (input == null) return null;
214+
215+
String clean = input;
216+
217+
// (1) <script> 태그 제거
218+
clean = clean.replaceAll("(?i)<script.*?>.*?</script>", "");
219+
220+
// (2) onclick, onerror 등 이벤트 핸들러 제거
221+
clean = clean.replaceAll("(?i)on\\w+\\s*=\\s*[\"'][^\"']*[\"']", "");
222+
223+
// (3) javascript: 프로토콜 제거
224+
clean = clean.replaceAll("(?i)javascript:", "");
225+
226+
return clean;
227+
}
228+
}
229+
```
230+
231+
---
232+
233+
## LAB1 - 소스코드의 XSS 취약점 확인
234+
235+
1. 환경 구축한 LAB을 실행시켜 크롬으로 로그인
236+
2. 게시판 메뉴 진입
237+
3. '쓰기' 버튼을 눌러 게시글 작성
238+
4. 제목 부분에 아래와 같이 입력
239+
`안녕하세요<script>alert('XSS!!');</script>`
240+
241+
5. 화면 아래로 내려가 '확인' 버튼
242+
6. 게시판 목록 화면에서 해당 게시글 제목에 스크립트 내용이 보여짐
243+
7. 해당 게시글을 클릭하면 스크립트가 동작하여 화면에
244+
경고창이 나타남
245+
246+
{:.prompt-warning}
247+
> XSS 취약점 있는 것이 확인됨
248+
>
249+

_posts/2025-10-01-SC(5-2).md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ last_modified_at: 2025-10-01
2121

2222
### OAuth2 구성 요소
2323

24-
![alt text](OAuth2comp.png)
24+
![alt text](../assets/img/CyberSecurity/OAuth2comp.png)
2525

26-
![alt text](OAuth2comp1.png)
26+
![alt text](../assets/img/CyberSecurity/OAuth2comp1.png)
2727

2828
#### Client Application (클라이언트)
2929
* **역할**: 사용자를 대신해 리소스에 접근하려는 앱/웹사이트
@@ -69,7 +69,7 @@ last_modified_at: 2025-10-01
6969

7070
### OAuth2 인증 흐름: Authorization Code Grant
7171

72-
![alt text](AuthorizationCodeGrant.png)
72+
![alt text](../assets/img/CyberSecurity/AuthorizationCodeGrant.png)
7373

7474
1. **사용자**: 애플리케이션에 서비스 접속 시도
7575
2. **애플리케이션**: 그 즉시 권한 서버의 인증 요청 페이지를 띄우도록 redirect
@@ -85,7 +85,7 @@ last_modified_at: 2025-10-01
8585
11. **리소스 서버**: 요청한 리소스 제공
8686
12. **애플리케이션:** 서비스 이용 화면 렌더링 후 사용자에게 서비스 제공
8787

88-
![alt text](AuthorizationCodeGrantseq.png)
88+
![alt text](../assets/img/CyberSecurity/AuthorizationCodeGrantseq.png)
8989
> 인증 흐름의 시퀀스 다이어그램
9090
9191
---
@@ -122,7 +122,7 @@ last_modified_at: 2025-10-01
122122

123123
### OAuth와 OAuth2 비교
124124

125-
![alt text](OAuthvsOAuth2.png)
125+
![alt text](../assets/img/CyberSecurity/OAuthvsOAuth2.png)
126126

127127
---
128128

@@ -133,11 +133,11 @@ https://cloud.google.com/apis?hl=ko
133133

134134
#### 2. 새 프로젝트 생성
135135

136-
![alt text](OAuth2create.png)
136+
![alt text](../assets/img/CyberSecurity/OAuth2create.png)
137137

138138
#### 3. 서비스 동의 및 시작
139139

140-
![alt text](OAuth2create1.png)
140+
![alt text](../assets/img/CyberSecurity/OAuth2create1.png)
141141

142142
#### 4. 프로젝트 구성
143143
* 앱 정보 > 앱 이름: `OAuth2 Test`, 사용자 지원 이메일: 개인 메일 주소
@@ -147,18 +147,18 @@ https://cloud.google.com/apis?hl=ko
147147

148148
#### 5. 클라이언트 만들기
149149

150-
![alt text](OAuth2create2.png)
150+
![alt text](../assets/img/CyberSecurity/OAuth2create2.png)
151151

152152
#### 6. 데이터 액세스 설정
153153

154-
![alt text](OAuth2create3.png)
154+
![alt text](../assets/img/CyberSecurity/OAuth2create3.png)
155155

156156
#### 7. 대상 설정
157157
* 대상 > 테스트 사용자 > + `ADD USERS`에 본인 메일 주소 입력
158158

159159
#### 8. 설정 확인 및 테스트
160160

161-
![alt text](OAuth2create4.png)
161+
![alt text](../assets/img/CyberSecurity/OAuth2create4.png)
162162

163163
* 아래 URL에 클라이언트 ID를 넣어 구글 로그인 창이 뜨는지 확인
164164
https://accounts.google.com/o/oauth2/auth?client_id=클라이언트ID&redirect_uri=http://localhost:8000/login/oauth2/code/google&response_type=code&scope=https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile
@@ -169,23 +169,23 @@ https://accounts.google.com/o/oauth2/auth?client_id=클라이언트ID&redirect_u
169169

170170
#### 10. LAB 환경에 소스 추가해서 OAuth2 연동 테스트
171171

172-
![alt text](OAuth2create5.png)
172+
![alt text](../assets/img/CyberSecurity/OAuth2create5.png)
173173
> LAB 소스코드 application.properties 설정 추가
174174
175-
![alt text](OAuth2create6.png)
175+
![alt text](../assets/img/CyberSecurity/OAuth2create6.png)
176176

177-
![alt text](OAuth2create7.png)
177+
![alt text](../assets/img/CyberSecurity/OAuth2create7.png)
178178

179-
![alt text](OAuth2create8.png)
179+
![alt text](../assets/img/CyberSecurity/OAuth2create8.png)
180180

181181
* 이제 LAB 코드를 실행시키고 앞서 시도해봤던 URL을 입력하여 구글 로그인 창이 나타나며, 계정을 선택하고 진행하면 STS 콘솔에 메시지가 제대로
182182
출력되면 성공
183183

184-
![alt text](OAuth2create9.png)
184+
![alt text](../assets/img/CyberSecurity/OAuth2create9.png)
185185

186186
#### Access Token 발급
187187

188-
![alt text](OAuth2create10.png)
188+
![alt text](../assets/img/CyberSecurity/OAuth2create10.png)
189189
> 기존 소셜로그인 메서드도 수정하고, getAccessToken 메서드도 추가
190190
191191
```java
@@ -218,7 +218,7 @@ private String getAccessToken(String authorizationCode, String registrationId) {
218218

219219
#### Resource Server에서 유저정보 받기
220220

221-
![alt text](OAuth2create11.png)
221+
![alt text](../assets/img/CyberSecurity/OAuth2create11.png)
222222

223223
```java
224224
//Access Token을 Authorization: Bearer 헤더에 포함하여 Google API 호출.
@@ -241,7 +241,7 @@ private JsonNode getUserResource(String accessToken, String registrationId) {
241241

242242
#### 유저 정보 토대로 계정 연동
243243

244-
![alt text](OAuth2create12.png)
244+
![alt text](../assets/img/CyberSecurity/OAuth2create12.png)
245245

246246
```java
247247
// 컨트롤러
@@ -259,7 +259,7 @@ response.setHeader("Set-Cookie", "JSESSIONID=" + session.getId() + "; Path=/; Ht
259259

260260
#### 로그인 성공
261261

262-
![alt text](OAuth2create13.png)
262+
![alt text](../assets/img/CyberSecurity/OAuth2create13.png)
263263

264264
---
265265

0 commit comments

Comments
 (0)