<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Aiden Lee.log</title>
        <link>https://velog.io/</link>
        <description>파인애플 좋아하세요?</description>
        <lastBuildDate>Wed, 24 Jun 2026 06:23:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. Aiden Lee.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/aiden_lee" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Git] 깃 커밋 컨벤션 가이드]]></title>
            <link>https://velog.io/@aiden_lee/Git-%EA%B9%83-%EC%BB%A4%EB%B0%8B-%EC%BB%A8%EB%B2%A4%EC%85%98-%EA%B0%80%EC%9D%B4%EB%93%9C</link>
            <guid>https://velog.io/@aiden_lee/Git-%EA%B9%83-%EC%BB%A4%EB%B0%8B-%EC%BB%A8%EB%B2%A4%EC%85%98-%EA%B0%80%EC%9D%B4%EB%93%9C</guid>
            <pubDate>Wed, 24 Jun 2026 06:23:02 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-커밋-메시지의-기본-구조">📌 커밋 메시지의 기본 구조</h2>
<p>좋은 커밋 메시지는 한눈에 변경 내용의 의도와 범위를 파악할 수 있어야 한다. 기본 구조는 제목(Subject), 본문(Body), 바닥글(Footer)의 3단계 구성을 따른다. 각 영역은 빈 줄(New Line)로 구분한다.</p>
<pre><code class="language-text">type(scope): 제목 (Subject)

본문 (Body) - 생략 가능

바닥글 (Footer) - 생략 가능
</code></pre>
<ul>
<li><strong>제목:</strong> 변경의 종류(type)와 핵심 내용을 한 줄로 요약한다.</li>
<li><strong>본문:</strong> &quot;무엇을&quot;, &quot;왜&quot; 변경했는지 상세히 서술한다. (선택 사항)</li>
<li><strong>바닥글:</strong> 이슈 트래커 ID(예: Jira, GitHub Issues)나 Breaking Change(중대 변경)를 명시한다. (선택 사항)</li>
</ul>
<hr>
<h2 id="🛠️-1-제목-subject-작성-규칙">🛠️ 1. 제목 (Subject) 작성 규칙</h2>
<p>제목은 컨벤션의 핵심이다. 현업에서 가장 많이 쓰이는 7가지 대표 <strong>Type</strong>을 숙지하고 일관되게 사용한다.</p>
<h3 id="7가지-핵심-커밋-타입-type">7가지 핵심 커밋 타입 (Type)</h3>
<table>
<thead>
<tr>
<th>타입 (Type)</th>
<th>언제 사용하는가?</th>
</tr>
</thead>
<tbody><tr>
<td><strong><code>feat</code></strong></td>
<td>새로운 기능(Feature)을 추가할 때</td>
</tr>
<tr>
<td><strong><code>fix</code></strong></td>
<td>버그를 수정할 때</td>
</tr>
<tr>
<td><strong><code>docs</code></strong></td>
<td>문서(README, 주석, 위키 등)를 수정할 때</td>
</tr>
<tr>
<td><strong><code>style</code></strong></td>
<td>코드 의미에 영향을 주지 않는 스타일 변경 (포맷팅, 세미콜론 누락 등)</td>
</tr>
<tr>
<td><strong><code>refactor</code></strong></td>
<td>기능 추가나 버그 수정 없이 코드를 리팩토링할 때</td>
</tr>
<tr>
<td><strong><code>test</code></strong></td>
<td>테스트 코드를 추가하거나 수정할 때</td>
</tr>
<tr>
<td><strong><code>chore</code></strong></td>
<td>빌드 업무, 패키지 매니저 설정, .gitignore 등 자잘한 기타 작업</td>
</tr>
</tbody></table>
<blockquote>
<p><strong>💡 Scope(범위) 활용하기 (선택)</strong>
변경 사항이 특정 모듈이나 도메인에 국한된다면 괄호를 이용해 범위를 명시한다. 한눈에 파악하기 매우 용이해진다.</p>
<ul>
<li>예: <code>feat(order): 주문 추가 시 중복 제약 조건 로직 구현</code></li>
<li>예: <code>chore(deps): lodash 라이브러리 버전 업데이트</code></li>
</ul>
</blockquote>
<h3 id="제목-작성-5대-원칙">제목 작성 5대 원칙</h3>
<ol>
<li><strong>타입 뒤에는 콜론과 공백을 둔다:</strong> <code>feat: 내용</code> (O) / <code>feat:내용</code> (X)</li>
<li><strong>첫 글자는 대문자로 시작하지 않는다:</strong> 영문 작성 시 소문자로 시작하는 것이 관례다. (타입과의 통일성)</li>
<li><strong>명령문 형태로 작성한다:</strong> &quot;<del>했음&quot; 보다는 &quot;</del>함&quot;, &quot;<del>추가&quot;, &quot;</del>수정&quot; 형태로 간결하게 작성한다.</li>
<li><strong>끝에 마침표(<code>.</code>)를 찍지 않는다.</strong></li>
<li><strong>글자 수는 50자 내외로 제한한다.</strong></li>
</ol>
<hr>
<h2 id="📝-2-본문-body-작성-규칙-선택-사항">📝 2. 본문 (Body) 작성 규칙 (선택 사항)</h2>
<p>변경의 맥락이 복잡하여 제목 한 줄로 서술이 불가능할 때 작성한다. 단순 버그 수정이나 자잘한 수정 시에는 과감히 생략한다.</p>
<ul>
<li>부연 설명이 필요할 때 사용하며, <strong>최대 72자</strong>마다 줄바꿈을 한다.</li>
<li>&quot;어떻게 변경했는지&quot;보다 <strong>&quot;무엇을&quot;, &quot;왜&quot; 변경했는지</strong>에 집중하여 작성한다.</li>
</ul>
<pre><code class="language-text">fix(auth): JWT 토큰 만료 시 간헐적 튕김 현상 수정

- 기존 익스파이어 타임 계산 로직의 시차 밀리초 계산 오류 확인
- 서버 타임존 기준과 브라우저 타임존을 UTC로 통일하여 오차 범위를 제거함
</code></pre>
<hr>
<h2 id="⚓-3-바닥글-footer-작성-규칙-선택-사항">⚓ 3. 바닥글 (Footer) 작성 규칙 (선택 사항)</h2>
<p>주로 협업 도구와의 연동이나 프로젝트의 중대한 변화를 알릴 때 사용한다.</p>
<h3 id="issue-tracker-연동-github-jira-등">Issue Tracker 연동 (GitHub, Jira 등)</h3>
<p>이슈 번호를 명시하여 해당 커밋이 어떤 태스크와 연결되어 있는지 추적할 수 있게 한다. GitHub의 경우 특정 키워드와 함께 사용하면 푸시 시 이슈가 자동으로 닫힌다.</p>
<ul>
<li>키워드: <code>Fixes</code>, <code>Closes</code>, <code>Resolves</code></li>
<li>예시: <code>규약 키워드: #이슈번호</code> ➡️ <code>Closes: #124</code></li>
</ul>
<h3 id="breaking-change-중대-변경-사항">BREAKING CHANGE (중대 변경 사항)</h3>
<p>이전 버전과의 하위 호환성이 깨지는 대대적인 API 변경이나 구조적 변경이 있을 때 바닥글 맨 앞에 <code>BREAKING CHANGE:</code>를 붙여 동료 개발자들에게 강력한 경고를 전달한다.</p>
<pre><code class="language-text">feat(api): V2 주문 인터페이스 스펙 변경

BREAKING CHANGE: 기존 /api/v1/order API가 폐기됨. 
이제 모든 클라이언트는 /api/v2/order 헤더 기반 인증 방식을 사용해야 함.

Ref: #204
Closes: #205
</code></pre>
<hr>
<h2 id="💡-현업-실용-팁-한-눈에-보는-올바른-예시">💡 현업 실용 팁: 한 눈에 보는 올바른 예시</h2>
<h3 id="올바른-예시-🟢">올바른 예시 🟢</h3>
<pre><code class="language-text">feat(cart): 장바구니 상품 수량 변경 API 연동

- 수량 변경 시 즉각적으로 총 금액이 리프레시되도록 훅 연결
- 최소 수량 1개 미만으로 내려갈 시 하단 경고 토스트 팝업 추가

Closes: #42
</code></pre>
<pre><code class="language-text">fix: 데이터베이스 연결 타임아웃 예외 처리 예외 구간 확장
</code></pre>
<pre><code class="language-text">style: 코드 포맷팅 및 사용하지 않는 임포트 구문 제거
</code></pre>
<h3 id="잘못된-예시-🔴">잘못된 예시 🔴</h3>
<pre><code class="language-text">Fix: 로그인 고쳤음. (타입 뒤 공백 없음, 마침표 사용, 과거형 서술)
</code></pre>
<pre><code class="language-text">수정 (영어 타입 미사용, 일관성 결여)
</code></pre>
<pre><code class="language-text">feat: 어제 짜다 만 장바구니 기능 마저 구현하고 중간 저장함 (지나치게 감정적이거나 사적인 서술)
</code></pre>
<hr>
<h2 id="🥊-요약">🥊 요약</h2>
<p>컨벤션은 절대적인 정답이 아니라 <strong>팀원 간의 약속</strong>이다. 위의 Conventional Commits 스타일을 기본 뼈대로 삼고, 팀의 성격에 맞게 조금씩 변형하여 활용한다면 누구나 읽기 편한 깔끔한 히스토리를 유지할 수 있다. 처음에는 어색할지라도 <code>type</code>을 먼저 정의하고 커밋하는 습관을 들이면 코드의 분리(Atomic Commit)도 자연스럽게 이루어지게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Portswigger]SSRF(2)]]></title>
            <link>https://velog.io/@aiden_lee/PortswiggerSSRF2</link>
            <guid>https://velog.io/@aiden_lee/PortswiggerSSRF2</guid>
            <pubDate>Wed, 13 May 2026 05:35:20 GMT</pubDate>
            <description><![CDATA[<p>SSRF Lecture
<a href="https://portswigger.net/web-security/ssrf">https://portswigger.net/web-security/ssrf</a></p>
<p>SSRF Lab
<a href="https://portswigger.net/web-security/all-labs#server-side-request-forgery-ssrf">https://portswigger.net/web-security/all-labs#server-side-request-forgery-ssrf</a></p>
<h2 id="circumventing-common-ssrf-defenses">Circumventing common SSRF defenses</h2>
<h3 id="ssrf-with-blacklist-based-input-filters">SSRF with blacklist-based input filters</h3>
<p>Some applications block input containing hostnames like 127.0.0.1 and localhost, or sensitive URLs like /admin. In this situation, you can often circumvent the filter using the following techniques:</p>
<p>Use an alternative IP representation of 127.0.0.1, such as 2130706433, 017700000001, or 127.1.</p>
<p>→ 다음과 같은 우회 방식을 시도해볼 수 있다.</p>
<ul>
<li>10진수(Decimal): 2130706433 (127.0.0.1을 10진수 정수로 변환한 값)</li>
<li>8진수(Octal): 017700000001 (각 마디를 8진수로 변환)</li>
<li>16진수(Hexadecimal): 0x7f000001</li>
<li>생략: 127.1 (중간의 0을 생략해도 운영체제는 127.0.0.1로 해석)</li>
</ul>
<p>Register your own domain name that resolves to 127.0.0.1. You can use spoofed.burpcollaborator.net for this purpose.</p>
<p>→ 127.0.0.1이라는 숫자 대신, 이 IP를 가리키는 도메인 이름을 사용</p>
<ul>
<li>원리: 서버 필터는 URL에 &quot;127&quot;이나 &quot;localhost&quot;가 있는지 검사한다. 하지만 공격자가 my-loopback.com이라는 도메인을 사고, 이 도메인의 DNS A 레코드를 127.0.0.1로 설정하면 필터는 일반적인 외부 도메인으로 인식하여 통과시킨다.</li>
<li>활용: Burp Suite의 spoofed.burpcollaborator.net처럼 이미 127.0.0.1로 연결되도록 설정된 공개 도메인을 사용할 수도 있다.</li>
</ul>
<p>Obfuscate blocked strings using URL encoding or case variation.</p>
<p>→ 난독화 (Obfuscation): 필터가 차단하는 특정 단어(예: /admin)를 알아보기 힘들게 비트는 방법</p>
<ul>
<li>URL 인코딩: /admin 대신 %61%64%6d%69%6e으로 전달한다. 서버 내부에서 이를 다시 디코딩하여 처리할 경우 필터를 우회하게 된다.</li>
<li>대소문자 변환: 필터가 대소문자를 구분한다면 /ADMIN 또는 /aDmIn으로 시도하여 차단을 피할 수 있다.</li>
</ul>
<p>Provide a URL that you control, which redirects to the target URL. Try using different redirect codes, as well as different protocols for the target URL. For example, switching from an http: to https: URL during the redirect has been shown to bypass some anti-SSRF filters.</p>
<p>→ 리다이렉트 활용 (HTTP Redirect): 서버가 입력받은 URL을 검사할 때와 실제로 접속할 때의 차이를 이용</p>
<ul>
<li>공격자가 제어하는 외부 서버(<a href="http://attacker.com/move)%EB%A5%BC">http://attacker.com/move)를</a> 입력한다.</li>
<li>서버의 필터는 &quot;외부 주소이므로 안전하다&quot;고 판단하고 요청을 허용한다.</li>
<li>공격자의 서버는 이 요청을 받을 때 302 Redirect 응답과 함께 Location: <a href="http://127.0.0.1/admin">http://127.0.0.1/admin</a> 헤더를 보낸다.</li>
<li>대상 서버는 리다이렉트 지시에 따라 내부의 127.0.0.1/admin으로 다시 접속하게 된다.</li>
<li>이 과정에서 프로토콜을 http:에서 https:로 바꾸거나 그 반대로 바꾸는 방식이 필터의 로직을 꼬이게 만들어 우회에 성공하기도 한다.</li>
</ul>
<h3 id="3-lab-ssrf-with-blacklist-based-input-filter">#3 Lab: SSRF with blacklist-based input filter</h3>
<p>This lab has a stock check feature which fetches data from an internal system.</p>
<p>To solve the lab, change the stock check URL to access the admin interface at <a href="http://localhost/admin">http://localhost/admin</a> and delete the user carlos.</p>
<p>The developer has deployed two weak anti-SSRF defenses that you will need to bypass.</p>
<hr>
<p>사용 툴: Burp Suite</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/70c73196-ef45-45e2-ac7c-5cab54723a2b/image.png" alt=""></p>
<p><code>http://127.1/</code> 또는 <code>http://2130706433/</code> 우회 시도 차단</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/62723f6a-606e-4062-b16c-d829a7b7c877/image.png" alt=""></p>
<p>URL 인코딩 <code>http://127.1/%61%64%6d%69%6e</code> 차단</p>
<p>이중 URL 인코딩 <code>http://127.1/%2561%2564%256d%2569%256e</code> 우회 시도 성공</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/b55ab195-7a37-400e-bb39-5cfc393c0a6a/image.png" alt=""></p>
<p><code>http://127.1/%2561%2564%256d%2569%256e/delete?username=carlos</code>로 삭제 성공</p>
<blockquote>
<p>LAB Solved!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/0637495a-4d06-4270-ac6d-b78f12659fe7/image.png" alt=""></p>
<hr>
<h3 id="ssrf-with-whitelist-based-input-filters">SSRF with whitelist-based input filters</h3>
<p>Some applications only allow inputs that match, a whitelist of permitted values. The filter may look for a match at the beginning of the input, or contained within in it. You may be able to bypass this filter by exploiting inconsistencies in URL parsing.</p>
<p>The URL specification contains a number of features that are likely to be overlooked when URLs implement ad-hoc parsing and validation using this method:</p>
<p>You can embed credentials in a URL before the hostname, using the <code>@</code> character.
For example: <code>https://expected-host:fakepassword@evil-host</code></p>
<p>You can use the <code>#</code> character to indicate a URL fragment.
For example: <code>https://evil-host#expected-host</code></p>
<p>You can leverage the DNS naming hierarchy to place required input into a fully-qualified DNS name that you control.
For example: <code>https://expected-host.evil-host</code></p>
<p>You can URL-encode characters to confuse the URL-parsing code. This is particularly useful if the code that implements the filter handles URL-encoded characters differently than the code that performs the back-end HTTP request. You can also try double-encoding characters; some servers recursively URL-decode the input they receive, which can lead to further discrepancies.
You can use combinations of these techniques together.</p>
<h3 id="4-lab-ssrf-with-whitelist-based-input-filter">#4 Lab: SSRF with whitelist-based input filter</h3>
<p>This lab has a stock check feature which fetches data from an internal system.</p>
<p>To solve the lab, change the stock check URL to access the admin interface at <a href="http://localhost/admin">http://localhost/admin</a> and delete the user carlos.</p>
<p>The developer has deployed an anti-SSRF defense you will need to bypass.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/da63c785-696b-4333-acff-acfd678abfef/image.png" alt=""></p>
<p>view details</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/ecda205f-06d1-4d2b-94bc-3bbd776a6b8b/image.png" alt=""></p>
<p>Check stock repeater로 보냄</p>
<p><code>stockApi=http://127.0.0.1/</code>로 변경하여 send
요청 차단됨. host는 <code>stock.weliketoshop.net</code>이어야만 함을 확인</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/4c55a483-3b33-4ef9-b943-445a5c73043f/image.png" alt=""></p>
<p><code>stockApi=http://username:password@stock.weliketoshop.net/</code>로 바꾸어 전송 시 500 응답을 받는 것 확인</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/6c800c97-6bf1-472d-aead-5fc2f78e6c1b/image.png" alt=""></p>
<p><code>stockApi=http://localhost:80%2523@stock.weliketoshop.net/</code></p>
<ul>
<li><p><code>http://localhost:80</code>: 도달하고자 하는 진짜 목적지</p>
</li>
<li><p><code>@</code>: URL에서 호스트명 앞에 사용자 이름이나 비밀번호를 넣을 때 사용하는 구분자</p>
</li>
<li><p><code>#</code> (%2523): 페이지 내부 위치를 나타내는 프래그먼트 구분자. 시스템은 # 이후의 문자열을 무시</p>
</li>
<li><p><code>stock.weliketoshop.net</code>: 서버가 허용한 Whitelist 목적지</p>
</li>
</ul>
<p><code>stockApi=http://localhost:80%2523@stock.weliketoshop.net/admin/delete?username=carlos</code></p>
<blockquote>
<p>LAB Solved!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/9e96b878-4df9-41e7-adf1-a06a5d42abf2/image.png" alt=""></p>
<h3 id="bypassing-ssrf-filters-via-open-redirection">Bypassing SSRF filters via open redirection</h3>
<p>Bypassing SSRF filters via open redirection
It is sometimes possible to bypass filter-based defenses by exploiting an open redirection vulnerability.</p>
<p>In the previous example, imagine the user-submitted URL is strictly validated to prevent malicious exploitation of the SSRF behavior. However, the application whose URLs are allowed contains an open redirection vulnerability. Provided the API used to make the back-end HTTP request supports redirections, you can construct a URL that satisfies the filter and results in a redirected request to the desired back-end target.</p>
<p>For example, the application contains an open redirection vulnerability in which the following URL:</p>
<pre><code>/product/nextProduct?currentProductId=6&amp;path=http://evil-user.net</code></pre><p>returns a redirection to:</p>
<pre><code>http://evil-user.net</code></pre><p>You can leverage the open redirection vulnerability to bypass the URL filter, and exploit the SSRF vulnerability as follows:</p>
<pre><code>POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 118

stockApi=http://weliketoshop.net/product/nextProduct?currentProductId=6&amp;path=http://192.168.0.68/admin</code></pre><p>This SSRF exploit works because the application first validates that the supplied stockAPI URL is on an allowed domain, which it is. The application then requests the supplied URL, which triggers the open redirection. It follows the redirection, and makes a request to the internal URL of the attacker&#39;s choosing.</p>
<h3 id="5-lab-ssrf-with-filter-bypass-via-open-redirection-vulnerability">#5 Lab: SSRF with filter bypass via open redirection vulnerability</h3>
<p>This lab has a stock check feature which fetches data from an internal system.</p>
<p>To solve the lab, change the stock check URL to access the admin interface at <a href="http://192.168.0.12:8080/admin">http://192.168.0.12:8080/admin</a> and delete the user carlos.</p>
<p>The stock checker has been restricted to only access the local application, so you will need to find an open redirect affecting the application first.</p>
<hr>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/c7960940-8134-43d8-adcc-e6fc93da0908/image.png" alt=""></p>
<p>View details -&gt; Check stock</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/1d1fcfc6-3506-44fd-a7b6-ee23c1305cdf/image.png" alt=""></p>
<p>Next product 선택 시 결과로 받는 <code>HTTP/2 302 Found</code> 응답 메세지를 통해 리다이렉트 응답임을 확인할 수 있음</p>
<p>이 때의 요청메세지에 <code>GET /product/nextProduct?currentProductId=2&amp;path=/product?productId=3</code>가 포함됨</p>
<p><code>GET /product/nextProduct?currentProductId=2&amp;path=http://192.168.0.12:8080/admin</code>에 대한 응답</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/b3899297-a851-43e9-b1df-3c1ad9ff27de/image.png" alt=""></p>
<p>리다이렉트 성공</p>
<p><code>stockApi=/product/nextProduct?path=http://192.168.0.12:8080/admin/delete?username=carlos</code>로 바꾸어 전송</p>
<blockquote>
<p>LAB Solved!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/d8b16ee0-1cc0-4ea9-abf0-52a759caa007/image.png" alt=""></p>
<h3 id="blind-ssrf-vulnerabilities">Blind SSRF vulnerabilities</h3>
<p>Blind SSRF vulnerabilities occur if you can cause an application to issue a back-end HTTP request to a supplied URL, but the response from the back-end request is not returned in the application&#39;s front-end response.</p>
<p>Blind SSRF is harder to exploit but sometimes leads to full remote code execution on the server or other back-end components.</p>
<h3 id="finding-hidden-attack-surface-for-ssrf-vulnerabilities">Finding hidden attack surface for SSRF vulnerabilities</h3>
<p>Many server-side request forgery vulnerabilities are easy to find, because the application&#39;s normal traffic involves request parameters containing full URLs. Other examples of SSRF are harder to locate.</p>
<h4 id="partial-urls-in-requests">Partial URLs in requests</h4>
<p>Sometimes, an application places only a hostname or part of a URL path into request parameters. The value submitted is then incorporated server-side into a full URL that is requested. If the value is readily recognized as a hostname or URL path, the potential attack surface might be obvious. However, exploitability as full SSRF might be limited because you do not control the entire URL that gets requested.</p>
<h4 id="urls-within-data-formats">URLs within data formats</h4>
<p>Some applications transmit data in formats with a specification that allows the inclusion of URLs that might get requested by the data parser for the format. An obvious example of this is the XML data format, which has been widely used in web applications to transmit structured data from the client to the server. When an application accepts data in XML format and parses it, it might be vulnerable to XXE injection. It might also be vulnerable to SSRF via XXE. We&#39;ll cover this in more detail when we look at XXE injection vulnerabilities.</p>
<h4 id="ssrf-via-the-referer-header">SSRF via the Referer header</h4>
<p>Some applications use server-side analytics software to tracks visitors. This software often logs the Referer header in requests, so it can track incoming links. Often the analytics software visits any third-party URLs that appear in the Referer header. This is typically done to analyze the contents of referring sites, including the anchor text that is used in the incoming links. As a result, the Referer header is often a useful attack surface for SSRF vulnerabilities.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTML/CSS]]></title>
            <link>https://velog.io/@aiden_lee/HTMLCSS</link>
            <guid>https://velog.io/@aiden_lee/HTMLCSS</guid>
            <pubDate>Sun, 10 May 2026 09:17:50 GMT</pubDate>
            <description><![CDATA[<ul>
<li>간단한 문법으로 원하는 대로 표현 가능한 시각화 도구</li>
<li>다른 언어들과 잘 섞이므로 활용이 좋음</li>
<li>간편하게 동작함, 접근성이 좋음</li>
</ul>
<h2 id="html">HTML</h2>
<p>대제목 : tag라고 부름
<Tag>content</Tag>
<Tag2><Tag1>content</Tag1></Tag2></p>
<p>대문자, 소문자 가리지 않음</p>
<p></p> : 가장 기본적인 태그
<h1></h1> : 헤딩1. 큰 헤드라인.


<p>문서의 골격</p>
<p>태그 사용 비율
<img src="https://velog.velcdn.com/images/aiden_lee/post/4b324d3b-da6d-4f17-97c6-8af1522f230b/image.png" alt=""></p>
<HTML> </HTML> : 이 문서는 html 문서이다 라는 표현
없어도 동작에 전혀 지장이 없으나 작성하고 있음

<!DOCTYPE html><p> : 문서의 최상단에 위치. 역시 이 문서는 html 문서이다 라는 표현</p>
<p>묶어서 꼭 작성하고 있음. 알아둘 것.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;/html&gt;</code></pre><p>html 문서는 두 파트로 나뉨</p>
<p>문서에 대한 정보. 작성자. 문서 제목 등</p>
<head></head> : 내용물에 대한 추가정보

<body></body> : 모든 내용물



<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;&lt;/head&gt;
    &lt;body&gt;&lt;/body&gt;
&lt;/html&gt;</code></pre><p>한글 사용하려는 경우</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;/head&gt;
    &lt;body&gt;&lt;/body&gt;
&lt;/html&gt;</code></pre><title></title> : 상단에 나타나는 글자

<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta charset=&quot;UTF-8&quot;&gt;
        &lt;title&gt;이력서&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;&lt;/body&gt;
&lt;/html&gt;</code></pre><p>body 태그 부분</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta charset=&quot;UTF-8&quot;&gt;
        &lt;title&gt;이력서 페이지&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;h1&gt;Hi&lt;/h1&gt;
        &lt;p&gt;content&lt;/p&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre><p>CSS</p>
<p>footer : 화면 최하단의 안내문</p>
<footer>content</footer>

<p>p : paragraph 문단. 일반적으로 쓰는 모든 글을 p</p>
<p>html 파일과 css 파일 분리
-연동하려면</p>
<p>html의 head 태그에 넣음
body에는 화면에 집적적으로 표현되는 컨텐츠만.
컨텐츠 표현을 위한 부수젖ㄱ인 내용은 head에</p>
<link></link>에. head부의 어느 위치에 있던 상관 없음.

<pre><code>  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;title&gt;김멋사의 이력서&lt;/title&gt;
    &lt;link rel=&quot;stylesheet&quot; href=&quot;codelion.css&quot;&gt;
  &lt;/head&gt;</code></pre><p>css 파일에서 꾸미기.</p>
<p>footer 꾸미기
footer{
    text-align: center; //가운데 정렬
    background-color: black;
}
내용물 순서는 상관 없음.</p>
<p>css의 기본 형태</p>
<p>Tag{
    text-align: center;
    color: orange;
}</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[One-Time Pad(OTP)]]></title>
            <link>https://velog.io/@aiden_lee/One-Time-PadOTP</link>
            <guid>https://velog.io/@aiden_lee/One-Time-PadOTP</guid>
            <pubDate>Sun, 10 May 2026 09:10:52 GMT</pubDate>
            <description><![CDATA[<h2 id="one-time-padotp">One-Time Pad(OTP)</h2>
<p>One-Time Pad(OTP, 일회용 패드)는 암호학 역사에서 정보이론적으로 완전한 보안(Perfect Secrecy) 이 증명된 대표적인 암호 체계다.
현대의 대부분의 암호 기술이 “현실적으로 해독이 매우 어려운 수준”의 안전성을 목표로 하는 반면, OTP는 이론적으로 공격자가 무한한 연산 능력을 가지고 있더라도 평문 정보를 알아낼 수 없다는 점에서 특별한 의미를 가진다.</p>
<p>다만 이러한 완벽성은 매우 까다로운 조건 위에서만 성립하며, 실제 운영 환경에서는 치명적인 제약이 존재한다
이 글에서는 OTP의 기본 원리와 완전 보안이 성립하는 이유, 그리고 실무에서 널리 사용되지 못하는 배경을 정리한다.</p>
<h3 id="one-time-pad의-원리">One-Time Pad의 원리</h3>
<p>OTP는 평문(Plaintext)과 동일한 길이의 무작위 키(Key)를 사용하여 암호화를 수행하는 방식이다.
현대 컴퓨터 환경에서는 일반적으로 비트 단위의 XOR(Exclusive OR) 연산을 사용한다.</p>
<h4 id="xor-연산">XOR 연산</h4>
<p>암호화:</p>
<blockquote>
<p>C=P⊕K</p>
</blockquote>
<ul>
<li>P: 평문(Plaintext)</li>
<li>K: 키(Key)</li>
<li>C: 암호문(Ciphertext)</li>
</ul>
<p>복호화:</p>
<blockquote>
<p>P=C⊕K</p>
</blockquote>
<p>XOR 연산의 특징상 같은 키를 다시 XOR하면 원래 데이터가 복원된다.</p>
<p>예를 들어</p>
<table>
<thead>
<tr>
<th>값</th>
<th>비트</th>
</tr>
</thead>
<tbody><tr>
<td>평문(P)</td>
<td>1010</td>
</tr>
<tr>
<td>키(K)</td>
<td>1100</td>
</tr>
<tr>
<td>암호문(C)</td>
<td>0110</td>
</tr>
</tbody></table>
<p>복호화:</p>
<p>0110⊕1100=1010</p>
<p>즉, 동일한 키만 알고 있다면 암호문으로부터 원래 평문을 정확히 복원할 수 있다.</p>
<p>수학자 클로드 샤논(Claude Shannon)은 특정 조건이 모두 충족될 경우 OTP가 Perfect Secrecy를 만족함을 증명했다.</p>
<p>이는 공격자가 암호문만 가지고는 평문에 대한 어떠한 정보도 얻을 수 없음을 의미한다.</p>
<p>OTP의 완전 보안은 다음 조건 위에서 성립한다.</p>
<ol>
<li>키 길이는 평문과 같아야 한다</li>
</ol>
<p>키가 충분히 길어야 모든 평문 비트를 독립적으로 가릴 수 있다.</p>
<p>즉:</p>
<p>∣K∣≥∣P∣</p>
<p>짧은 키를 반복 사용하면 패턴이 발생하며 보안성이 붕괴한다.</p>
<ol start="2">
<li>키는 진정한 무작위(True Random)여야 한다</li>
</ol>
<p>키는 예측 가능해서는 안 된다.</p>
<p>의사난수(PRNG)가 아닌, 통계적 편향이 없는 진정한 난수여야 하며 공격자가 패턴을 추론할 수 없어야 한다.</p>
<ol start="3">
<li>키는 단 한 번만 사용해야 한다</li>
</ol>
<p>“One-Time”이라는 이름 그대로, 동일한 키를 두 번 이상 사용해서는 안 된다.</p>
<p>키 재사용이 발생하면 암호문 간 관계 분석이 가능해지며 OTP의 핵심 보안성이 무너진다.</p>
<p>(4) 키는 완전히 비밀이어야 한다</p>
<p>키를 알고 있는 주체는 송신자와 수신자뿐이어야 한다.</p>
<p>만약 키가 노출된다면 OTP는 일반 평문과 다를 바 없는 상태가 된다.</p>
<h3 id="한계-및-단점">한계 및 단점</h3>
<p>OTP는 이론적으로 완벽하지만, 현실에서는 매우 비실용적이다.</p>
<p>현대 인터넷 보안에서 TLS, AES, RSA 같은 방식이 사용되는 이유도 여기에 있다.</p>
<ol>
<li>키 분배 문제(Key Distribution Problem)</li>
</ol>
<p>가장 큰 문제는 키 전달이다.</p>
<p>OTP는 평문과 동일한 길이의 키를 미리 안전하게 공유해야 한다.
예를 들어 1GB 데이터를 암호화하려면 1GB 길이의 무작위 키가 필요하다.</p>
<p>즉, 대규모 통신 환경에서는 키를 안전하게 생성·전달·동기화하는 비용이 지나치게 커진다.</p>
<ol start="2">
<li>키 저장 비용</li>
</ol>
<p>대용량 데이터를 처리하는 현대 시스템에서는 데이터 크기만큼의 키를 저장해야 한다.</p>
<p>예를 들어:</p>
<p>1TB 데이터 → 1TB 무작위 키 필요
10TB 데이터 → 10TB 키 필요</p>
<p>이는 운영 효율 측면에서 매우 부담이 크다.</p>
<ol start="3">
<li>키 재사용 시 보안 붕괴</li>
</ol>
<p>동일한 키를 두 번 사용하면 다음 관계가 성립한다.</p>
<blockquote>
<p>C1⊕C2=P1⊕P2</p>
</blockquote>
<p>즉, 키가 상쇄되면서 두 평문 간의 관계 정보가 드러난다.</p>
<p>언어 데이터는 통계적 중복성을 가지므로, 공격자는 이를 기반으로 평문 일부를 추론할 수 있다.</p>
<p>실제 역사적으로도 OTP 키 재사용은 여러 정보기관 암호 체계 붕괴의 원인이 되었다.</p>
<h3 id="사용사례">사용사례</h3>
<ol>
<li>냉전 시대 정보기관</li>
</ol>
<p>냉전 시기 스파이 활동에서는 난수가 기록된 종이 패드(Pad)를 사용했다.</p>
<p>암호화 후 사용한 페이지는 즉시 폐기했으며, 여기서 “One-Time Pad”라는 이름이 유래했다.</p>
<ol start="2">
<li>국가 간 통신</li>
</ol>
<p>미국과 소련 간 핫라인 같은 최고 수준 기밀 통신에서도 OTP 기반 방식이 연구·활용되었다.</p>
<ol start="3">
<li>양자 키 분배(QKD)</li>
</ol>
<p>현대에는 양자역학 기반의 QKD(Quantum Key Distribution)를 이용해 OTP용 키를 안전하게 분배하려는 연구가 진행되고 있다.</p>
<p>OTP 자체는 오래된 기술이지만, 안전한 키 분배 문제를 해결하려는 시도는 여전히 현대 암호학의 중요한 연구 주제다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Portswigger]SSRF(1)]]></title>
            <link>https://velog.io/@aiden_lee/PortswiggerSSRF1</link>
            <guid>https://velog.io/@aiden_lee/PortswiggerSSRF1</guid>
            <pubDate>Fri, 24 Apr 2026 05:29:48 GMT</pubDate>
            <description><![CDATA[<h3 id="ssrf-lecture">SSRF Lecture</h3>
<p><a href="https://portswigger.net/web-security/ssrf">https://portswigger.net/web-security/ssrf</a></p>
<h3 id="ssrf-lab">SSRF Lab</h3>
<p><a href="https://portswigger.net/web-security/all-labs#server-side-request-forgery-ssrf">https://portswigger.net/web-security/all-labs#server-side-request-forgery-ssrf</a></p>
<h2 id="ssrf란">SSRF란?</h2>
<p>Server-side request forgery is a web security vulnerability that allows an attacker to cause the server-side application to make requests to an unintended location.</p>
<h3 id="ssrf-공격">SSRF 공격</h3>
<p>A successful SSRF attack can often result in unauthorized actions or access to data within the organization. This can be in the vulnerable application, or on other back-end systems that the application can communicate with. In some situations, the SSRF vulnerability might allow an attacker to perform arbitrary command execution.</p>
<p>An SSRF exploit that causes connections to external third-party systems might result in malicious onward attacks. These can appear to originate from the organization hosting the vulnerable application.</p>
<h3 id="1-lab-basic-ssrf-against-the-local-server">#1 Lab: Basic SSRF against the local server</h3>
<p>This lab has a stock check feature which fetches data from an internal system.</p>
<p>To solve the lab, change the stock check URL to access the admin interface at <a href="http://localhost/admin">http://localhost/admin</a> and <strong>delete the user carlos.</strong></p>
<hr>
<p>사용 툴: Burp Suite</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/bf0d5add-b3af-40ad-b495-0647b5573a84/image.png" alt=""></p>
<p>View details 버튼을 눌러 제품 상세 페이지로 이동한다.</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/100efa09-4f84-4bb8-b3cf-c195fd960ca4/image.png" alt=""></p>
<p>제품 상세 하단에 Check stock으로 이동 인터셉트</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/1f3db64d-3255-4946-bfac-b3128c30b332/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/d854ed95-355e-40cd-8a72-19bbc1c16405/image.png" alt=""></p>
<p><code>stockApi=http://localhost/admin</code>로 request 메시지 조작하여 forward</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/c36ef30e-5b1e-43d9-b9c9-03c81823aa8e/image.png" alt=""></p>
<p>carlos 삭제 시도 실패</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/12dc6a52-39e2-4e88-a824-29ee83db38d5/image.png" alt=""></p>
<p>이 때의 요청이 <code>https://0ac8004404c2c3d581f9444800900029.web-security-academy.net/admin/delete?username=carlos</code>임을 확인</p>
<p><code>stockApi=http://localhost/admin/delete?username=carlos</code>로 request 메시지 조작하여 다시 Check stock 인터셉트 및 forward</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/b79a905a-9110-4d3f-8e26-ecd98668881d/image.png" alt=""></p>
<blockquote>
<p>LAB Solved!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/ba587ee8-fd9d-4334-8b2b-b715465bbdc9/image.png" alt=""></p>
<hr>
<h3 id="why-do-applications-behave-in-this-way-and-implicitly-trust-requests-that-come-from-the-local-machine">Why do applications behave in this way, and implicitly trust requests that come from the local machine?</h3>
<ul>
<li><p>The access control check might be implemented in a different component that sits in front of the application server. When a connection is made back to the server, the check is bypassed.</p>
</li>
<li><p>For disaster recovery purposes, the application might allow administrative access without logging in, to any user coming from the local machine. This provides a way for an administrator to recover the system if they lose their credentials. This assumes that only a fully trusted user would come directly from the server.</p>
</li>
<li><p>The administrative interface might listen on a different port number to the main application, and might not be reachable directly by users.</p>
</li>
</ul>
<h3 id="2-lab-basic-ssrf-against-another-back-end-system">#2 Lab: Basic SSRF against another back-end system</h3>
<p>This lab has a stock check feature which fetches data from an internal system.</p>
<p>To solve the lab, use the stock check functionality to scan the internal 192.168.0.X range for an admin interface on port 8080, then use it to delete the user carlos.</p>
<hr>
<p>사용 툴: Burp Suite</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/228fe252-023b-453c-963a-55e39dbba27a/image.png" alt=""></p>
<p>View details에서, Check stock을 intruder로 보내 자동화 공격 수행</p>
<p><code>stockApi=http://192.168.0.1:8080/</code>에서 1에 대해 Add
Payload를 다음과 같이 설정</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/a6e374c6-e7f7-4717-88b2-1fa9bee3a4a5/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/8a1936b6-96f8-4888-a71b-7b372dd8bfd3/image.png" alt=""></p>
<p>공격 수행</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/5cb8e366-ff94-4bc8-b883-da9afef45cb1/image.png" alt=""></p>
<p>200 응답 발견</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/249d169d-a1e4-4e93-850e-6967fa0db3a1/image.png" alt=""></p>
<p><code>stockApi=http://192.168.0.215:8080/admin</code> 요청 조작</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/70a0e2f7-71f3-4be9-b85c-a5926f3f0c4e/image.png" alt=""></p>
<p><code>stockApi=http://192.168.0.215:8080/admin/delete?username=carlos</code> 요청 조작</p>
<blockquote>
<p>LAB Solved!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/1748d05a-9916-4b16-9ba4-830612aa3125/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[IP:127.0.0.1, 192.168.0.X]]></title>
            <link>https://velog.io/@aiden_lee/IP</link>
            <guid>https://velog.io/@aiden_lee/IP</guid>
            <pubDate>Fri, 24 Apr 2026 05:28:58 GMT</pubDate>
            <description><![CDATA[<h3 id="127001-loopback-address">127.0.0.1 (Loopback Address)</h3>
<p>127.0.0.1은 네트워크 인터페이스를 거치지 않고 시스템 내부에서 통신하기 위해 예약된 루프백(Loopback) 주소다. 보통 &#39;localhost&#39;라는 호스트명과 매핑되어 사용된다.</p>
<ul>
<li><p>자기 참조성: 외부 네트워크망에 연결되어 있지 않더라도 운영체제 내부의 네트워크 스택을 통해 자기 자신에게 데이터를 전송한다.</p>
</li>
<li><p>용도: 로컬 환경에서의 웹 서버 구동 테스트, 애플리케이션 디버깅, 데이터베이스 연결 확인 등 내부 프로세스 간 통신에 사용된다.</p>
</li>
<li><p>IPv6 대응: IPv6 규격에서는 ::1이 동일한 역할을 수행한다.</p>
</li>
</ul>
<h3 id="1921680x-private-ip-address">192.168.0.X (Private IP Address)</h3>
<p>192.168.0.0/24 대역은 RFC 1918 표준에 의해 정의된 사설 IP(Private IP) 주소 공간이다.</p>
<ul>
<li><p>접근 제한: 사설 IP는 인터넷 라우팅이 불가능하도록 설계되어 있다. 외부 인터넷 환경에서 해당 주소로 직접 패킷을 전송하면 ISP의 라우터에서 이를 폐기한다.</p>
</li>
<li><p>할당 배경: 공인 IP 주소(Public IP)의 고갈 문제를 해결하기 위해 도입되었다. NAT(Network Address Translation) 기술을 사용하여 내부망 기기들은 사설 IP를 쓰고, 외부와 통신할 때만 공인 IP를 공유한다.</p>
</li>
<li><p>SSRF와의 관계: 외부에서 접근할 수 없는 내부망 시스템이라도, 내부망에 걸쳐 있는 웹 서버가 공격자의 조작된 요청을 받아 대신 통신을 수행할 경우 보안 경계가 무력화될 수 있다.</p>
</li>
</ul>
<h3 id="ip-스캔-범위와-주소-예약-규정">IP 스캔 범위와 주소 예약 규정</h3>
<p>네트워크 대역 스캔 시 192.168.0.1부터 시작하는 이유는 특정 주소들이 특수 용도로 예약되어 있기 때문이다.</p>
<p>192.168.0.0 (Network Address): 해당 네트워크 대역 자체를 식별하는 주소다. 실제 호스트(기기)에 할당할 수 없으므로 통신 대상이 될 수 없다.</p>
<p>192.168.0.255 (Broadcast Address): 네트워크 내의 모든 호스트에게 데이터를 동시에 전송하기 위한 브로드캐스트 주소다. 개별 서비스나 관리자 인터페이스가 존재할 수 없다.</p>
<p>192.168.0.1 (Gateway): 관례적으로 네트워크의 첫 번째 가용한 주소는 게이트웨이(라우터)에 할당된다. 따라서 관리자 인터페이스나 설정 페이지가 존재할 가능성이 가장 높은 지점이다.</p>
<p>따라서 유효한 호스트가 존재할 수 있는 범위는 네트워크 주소와 브로드캐스트 주소를 제외한 .1부터 .254까지다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2026 주요정보통신기반시설 기술적 취약점 분석·평가 방법 상세가이드 - 웹 서비스]]></title>
            <link>https://velog.io/@aiden_lee/2026-%EC%A3%BC%EC%9A%94%EC%A0%95%EB%B3%B4%ED%86%B5%EC%8B%A0%EA%B8%B0%EB%B0%98%EC%8B%9C%EC%84%A4-%EA%B8%B0%EC%88%A0%EC%A0%81-%EC%B7%A8%EC%95%BD%EC%A0%90-%EB%B6%84%EC%84%9D%ED%8F%89%EA%B0%80-%EB%B0%A9%EB%B2%95-%EC%83%81%EC%84%B8%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%9B%B9-%EC%84%9C%EB%B9%84%EC%8A%A4</link>
            <guid>https://velog.io/@aiden_lee/2026-%EC%A3%BC%EC%9A%94%EC%A0%95%EB%B3%B4%ED%86%B5%EC%8B%A0%EA%B8%B0%EB%B0%98%EC%8B%9C%EC%84%A4-%EA%B8%B0%EC%88%A0%EC%A0%81-%EC%B7%A8%EC%95%BD%EC%A0%90-%EB%B6%84%EC%84%9D%ED%8F%89%EA%B0%80-%EB%B0%A9%EB%B2%95-%EC%83%81%EC%84%B8%EA%B0%80%EC%9D%B4%EB%93%9C-%EC%9B%B9-%EC%84%9C%EB%B9%84%EC%8A%A4</guid>
            <pubDate>Thu, 05 Mar 2026 01:41:56 GMT</pubDate>
            <description><![CDATA[<ol>
<li>계정 관리</li>
<li>서비스 관리</li>
<li>보안 설정</li>
<li>패치 및 로그 관리</li>
</ol>
<ol>
<li>계정 관리</li>
</ol>
<table>
<thead>
<tr>
<th>점검항목</th>
<th>항목 중요도</th>
<th>항목코드</th>
</tr>
</thead>
<tbody><tr>
<td>Default 관리자 계정명 변경</td>
<td>상</td>
<td>WEB-1</td>
</tr>
<tr>
<td>취약한 비밀번호 사용 제한</td>
<td>상</td>
<td>WEB-2</td>
</tr>
<tr>
<td>비밀번호 파일 권한 관리</td>
<td>상</td>
<td>WEB-3</td>
</tr>
</tbody></table>
<ol start="2">
<li>서비스 관리</li>
</ol>
<table>
<thead>
<tr>
<th>점검항목</th>
<th>항목 중요도</th>
<th>항목코드</th>
</tr>
</thead>
<tbody><tr>
<td>웹 서비스 디렉터리 리스팅 방지 설정</td>
<td>상</td>
<td>WEB-4</td>
</tr>
<tr>
<td>지정하지 않은 CGI/ISAPI 실행 제한</td>
<td>상</td>
<td>WEB-5</td>
</tr>
<tr>
<td>웹 서비스 상위 디렉터리 접근 제한 설정</td>
<td>상</td>
<td>WEB-6</td>
</tr>
<tr>
<td>웹 서비스 경로 내 불필요한 파일 제거</td>
<td>중</td>
<td>WEB-7</td>
</tr>
<tr>
<td>웹 서비스 파일 업로드 및 다운로드 용량 제한</td>
<td>하</td>
<td>WEB-8</td>
</tr>
<tr>
<td>웹 서비스 프로세스 권한 제한</td>
<td>상</td>
<td>WEB-9</td>
</tr>
<tr>
<td>불필요한 프록시 설정 제한</td>
<td>상</td>
<td>WEB-10</td>
</tr>
<tr>
<td>웹 서비스 경로 설정</td>
<td>중</td>
<td>WEB-11</td>
</tr>
<tr>
<td>웹 서비스 링크 사용 금지</td>
<td>중</td>
<td>WEB-12</td>
</tr>
<tr>
<td>웹 서비스 설정 파일 노출 제한</td>
<td>상</td>
<td>WEB-13</td>
</tr>
<tr>
<td>웹 서비스 경로 내 파일의 접근 통제</td>
<td>상</td>
<td>WEB-14</td>
</tr>
<tr>
<td>웹 서비스의 불필요한 스크립트 매핑 제거</td>
<td>상</td>
<td>WEB-15</td>
</tr>
<tr>
<td>웹 서비스 헤더 정보 노출 제한</td>
<td>중</td>
<td>WEB-16</td>
</tr>
<tr>
<td>웹 서비스 가상 디렉토리 삭제</td>
<td>중</td>
<td>WEB-17</td>
</tr>
<tr>
<td>웹 서비스 WebDAV 비활성화</td>
<td>상</td>
<td>WEB-18</td>
</tr>
</tbody></table>
<ol start="3">
<li>보안 설정</li>
</ol>
<table>
<thead>
<tr>
<th>점검항목</th>
<th>항목 중요도</th>
<th>항목코드</th>
</tr>
</thead>
<tbody><tr>
<td>웹 서비스 SSI(Server Side Includes) 사용 제한</td>
<td>중</td>
<td>WEB-19</td>
</tr>
<tr>
<td>SSL/TLS 활성화</td>
<td>상</td>
<td>WEB-20</td>
</tr>
<tr>
<td>HTTP 리디렉션</td>
<td>중</td>
<td>WEB-21</td>
</tr>
<tr>
<td>에러 페이지 관리</td>
<td>하</td>
<td>WEB-22</td>
</tr>
<tr>
<td>LDAP 알고리즘 적절하게 구성</td>
<td>중</td>
<td>WEB-23</td>
</tr>
</tbody></table>
<ol start="4">
<li>패치 및 로그 관리</li>
</ol>
<table>
<thead>
<tr>
<th>점검항목</th>
<th>항목 중요도</th>
<th>항목코드</th>
</tr>
</thead>
<tbody><tr>
<td>별도의 업로드 경로 사용 및 권한 설정</td>
<td>중</td>
<td>WEB-24</td>
</tr>
<tr>
<td>주기적 보안 패치 및 벤더 권고사항 적용</td>
<td>상</td>
<td>WEB-25</td>
</tr>
<tr>
<td>로그 디렉터리 및 파일 권한 설정</td>
<td>중</td>
<td>WEB-26</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[2026 주요정보통신기반시설 기술적 취약점 분석·평가 방법 상세가이드 - Web Application(웹)
]]></title>
            <link>https://velog.io/@aiden_lee/2026-%EC%A3%BC%EC%9A%94%EC%A0%95%EB%B3%B4%ED%86%B5%EC%8B%A0%EA%B8%B0%EB%B0%98%EC%8B%9C%EC%84%A4-%EA%B8%B0%EC%88%A0%EC%A0%81-%EC%B7%A8%EC%95%BD%EC%A0%90-%EB%B6%84%EC%84%9D%ED%8F%89%EA%B0%80-%EB%B0%A9%EB%B2%95-%EC%83%81%EC%84%B8%EA%B0%80%EC%9D%B4%EB%93%9C-Web-Application%EC%9B%B9</link>
            <guid>https://velog.io/@aiden_lee/2026-%EC%A3%BC%EC%9A%94%EC%A0%95%EB%B3%B4%ED%86%B5%EC%8B%A0%EA%B8%B0%EB%B0%98%EC%8B%9C%EC%84%A4-%EA%B8%B0%EC%88%A0%EC%A0%81-%EC%B7%A8%EC%95%BD%EC%A0%90-%EB%B6%84%EC%84%9D%ED%8F%89%EA%B0%80-%EB%B0%A9%EB%B2%95-%EC%83%81%EC%84%B8%EA%B0%80%EC%9D%B4%EB%93%9C-Web-Application%EC%9B%B9</guid>
            <pubDate>Wed, 04 Mar 2026 07:52:44 GMT</pubDate>
            <description><![CDATA[<table>
<thead>
<tr>
<th>점검항목</th>
<th>항목 중요도</th>
<th>항목코드</th>
</tr>
</thead>
<tbody><tr>
<td>코드 인젝션 (CodeInjection)</td>
<td>상</td>
<td>CI</td>
</tr>
<tr>
<td>SQL 인젝션 (SQL Injection)</td>
<td>상</td>
<td>SI</td>
</tr>
<tr>
<td>디렉터리 인덱싱</td>
<td>상</td>
<td>DI</td>
</tr>
<tr>
<td>에러 페이지 적용 미흡</td>
<td>상</td>
<td>EP</td>
</tr>
<tr>
<td>정보 누출</td>
<td>상</td>
<td>IL</td>
</tr>
<tr>
<td>크로스사이트 스크립트</td>
<td>상</td>
<td>XS</td>
</tr>
<tr>
<td>크로스사이트 요청 위조(CSRF)</td>
<td>상</td>
<td>CF</td>
</tr>
<tr>
<td>서버사이드 요청 위조(SSRF)</td>
<td>상</td>
<td>SF</td>
</tr>
<tr>
<td>약한 비밀번호 정책</td>
<td>상</td>
<td>BF</td>
</tr>
<tr>
<td>불충분한 인증 절차</td>
<td>상</td>
<td>IA</td>
</tr>
<tr>
<td>불충분한 권한 검증</td>
<td>상</td>
<td>IN</td>
</tr>
<tr>
<td>취약한 비밀번호 복구 절차</td>
<td>상</td>
<td>PR</td>
</tr>
<tr>
<td>프로세스 검증 누락</td>
<td>상</td>
<td>PV</td>
</tr>
<tr>
<td>악성 파일 업로드</td>
<td>상</td>
<td>FU</td>
</tr>
<tr>
<td>파일 다운로드</td>
<td>상</td>
<td>FD</td>
</tr>
<tr>
<td>불충분한 세션 관리</td>
<td>상</td>
<td>IS</td>
</tr>
<tr>
<td>데이터 평문 전송</td>
<td>상</td>
<td>SN</td>
</tr>
<tr>
<td>쿠키 변조</td>
<td>상</td>
<td>CC</td>
</tr>
<tr>
<td>관리자 페이지 노출</td>
<td>상</td>
<td>AE</td>
</tr>
<tr>
<td>자동화 공격</td>
<td>상</td>
<td>AU</td>
</tr>
<tr>
<td>불필요한 Method 악용</td>
<td>상</td>
<td>WM</td>
</tr>
</tbody></table>
]]></description>
        </item>
        <item>
            <title><![CDATA[클라우드 기반의 보안 컨설팅 실무 DAY1]]></title>
            <link>https://velog.io/@aiden_lee/%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EA%B8%B0%EB%B0%98%EC%9D%98-%EB%B3%B4%EC%95%88-%EC%BB%A8%EC%84%A4%ED%8C%85-%EC%8B%A4%EB%AC%B4-DAY1</link>
            <guid>https://velog.io/@aiden_lee/%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EA%B8%B0%EB%B0%98%EC%9D%98-%EB%B3%B4%EC%95%88-%EC%BB%A8%EC%84%A4%ED%8C%85-%EC%8B%A4%EB%AC%B4-DAY1</guid>
            <pubDate>Sat, 31 Jan 2026 07:48:53 GMT</pubDate>
            <description><![CDATA[<p>ISMS(정보보호 관리체계)
ISMS-P(정보보호 및 개인정보보호 관리체계)</p>
<h4 id="os의-eos와-eol">OS의 EOS와 EOL</h4>
<ol>
<li><p>EOS(End of Support) - 지원 종료
제품의 공식적인 지원 종료
새로운 취약점 발견 시 제조사는 조치를 취하지 않음.</p>
</li>
<li><p>EOL(End of Life) - 수명 종료
운영체제의 수명 자체가 종료</p>
</li>
</ol>
<p>보안의 세가지 요소</p>
<p>TCP/IP 7layer</p>
<h4 id="정보보안-및-개인정보보호-전문가">정보보안 및 개인정보보호 전문가</h4>
<ol>
<li>관련 자격</li>
</ol>
<p>1.3 개인정보 영향평가
2. 진로 및 준비 방안</p>
<p>tenant
tenacy</p>
<p><a href="https://cloudsecurityalliance.org/artifacts/top-threats-to-cloud-computing-egregious-eleven-korean-translation">CSA 클라우드 보안 위협</a>
<a href="https://www.tatumsecurity.com/articles/csa-2025-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EB%B3%B4%EC%95%88-%EC%9C%84%ED%98%91-%EB%A6%AC%ED%8F%AC%ED%8A%B8-%EC%8B%A4%EC%A0%9C-%ED%95%B4%ED%82%B9-%EC%82%AC%EB%A1%80%EB%A1%9C-%EB%B0%B0%EC%9A%B0%EB%8A%94-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C%EC%9D%98-%EC%9C%84%ED%97%98">참고</a></p>
<h4 id="on-promise-vs-cloud-service">On-Promise vs Cloud Service</h4>
<p>클라우드 컴퓨팅의 책임 공유 모델</p>
<ul>
<li><p>CSP(Cloud Service Provider, 클라우드 서비스 제공업체) - AWS, Azure, GCP, 네이버클라우드 등과 같이 인터넷을 통해 컴퓨팅, 스토리지, 데이터베이스, 네트워크 등 클라우드 기반 리소스를 주문형으로 제공하는 제3자 회사</p>
</li>
<li><p>MSP(Managed Service Provider, 매니지드 서비스 프로바이더) - 기업의 클라우드 환경 및 IT 인프라 설계, 구축, 운영, 유지보수를 전담하여 관리하는 전문 파트너사</p>
</li>
<li><p>CSC (Cloud Service Customer, 클라우드 서비스 고객) - 클라우드 서비스를 이용하는 기업이나 개인.</p>
</li>
<li><p>NFV(Network Functions Virtualization, 네트워크 기능 가상화) - 라우터, 방화벽 등 전용 하드웨어 기반의 네트워크 장비를 가상 머신(VM)이나 컨테이너 등 소프트웨어(VNF)로 구현하여 범용 서버에서 실행하는 기술</p>
</li>
<li><p>VPC(Virtual Private Cloud, 가상 프라이빗 클라우드) - 퍼블릭 클라우드 제공업체(AWS, NCP 등) 내에서 논리적으로 격리된 사용자 전용 가상 네트워크 공간</p>
</li>
<li><p>NACL(Network Access Control List) - 클라우드(AWS 등) 및 네트워크 환경에서 서브넷(Subnet) 단위로 들어오고 나가는 트래픽을 제어하는 스테이트리스(Stateless) 방화벽
<a href="https://guide.ncloud-docs.com/docs/vpc-nacl-vpc">참고</a></p>
</li>
</ul>
<h4 id="정보보호관리체계-인증isms-p-vs-클라우드-보안-인증csap">정보보호관리체계 인증(ISMS-P) VS 클라우드 보안 인증(CSAP)</h4>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 크롤링]]></title>
            <link>https://velog.io/@aiden_lee/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%81%AC%EB%A1%A4%EB%A7%81</link>
            <guid>https://velog.io/@aiden_lee/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%81%AC%EB%A1%A4%EB%A7%81</guid>
            <pubDate>Fri, 30 Jan 2026 05:55:55 GMT</pubDate>
            <description><![CDATA[<h2 id="requests-라이브러리">requests 라이브러리</h2>
<pre><code># 라이브러리 설치
!pip install requests

# 파이썬 코드로 http 요청을 보낼 수 있게 해주는 라이브러리
import requests

# http 요청을 보낼 url
url = &quot;https://www.bookspot.store/&quot;</code></pre><h3 id="get">GET</h3>
<p>requests 라이브러리의 get 메소드를 알아보자.</p>
<pre><code># HTTP GET 요청을 보내는 함수(메소드)
requests.get(url)</code></pre><p>-&gt;이 주소(url)에 접속해서 데이터를 주세요&quot;라고 서버에 요청하는 코드</p>
<p>❗<strong>HTTP GET</strong>
웹에서 데이터를 가져올 때 사용하는 요청 방식</p>
<h4 id="구조-설명">구조 설명</h4>
<pre><code>response = requests.get(url)</code></pre><blockquote>
<p>requests - HTTP 요청을 보내는 라이브러리
get - GET 방식으로 요청
url - 접속할 웹 주소
response - 서버가 보내준 응답 객체</p>
</blockquote>
<p><strong>response 객체의 속성</strong></p>
<pre><code>response.text        # HTML 코드
response.status_code # 상태 코드 (200이면 성공)
response.headers     # 응답 헤더
response.content     # 바이너리 데이터</code></pre><h4 id="내부동작">내부동작</h4>
<pre><code>requests.get(url)</code></pre><ol>
<li>서버에 HTTP GET 요청을 보냄</li>
<li>서버가 그 요청을 처리함</li>
<li>서버가 응답(HTML, JSON 등)을 돌려줌</li>
<li>그 응답을 response 객체로 받음</li>
</ol>
<h4 id="파라미터-전달">파라미터 전달</h4>
<pre><code>requests.get(&quot;https://example.com/search&quot;, params={&quot;q&quot;: &quot;python&quot;})</code></pre><p>실제 요청 주소:</p>
<pre><code>https://example.com/search?q=python</code></pre><h2 id="beautifulsoup-라이브러리">beautifulsoup 라이브러리</h2>
<pre><code># pip install requests beautifulsoup4
!pip install requests beautifulsoup4
</code></pre><h3 id="select">.select()</h3>
<p>BeautifulSoup 라이브러리에서 <strong>CSS 선택자(CSS Selector)</strong>를 사용해 HTML 요소를 선택하는 메서드
유사한 것으로는 .select_one(), .find(), .find_all()이라는 것도 있다.</p>
<p>사용법
형식: soup.select(선택자)<br>지정한 태그, 속성, id 등을 찾아서 리스트로 반환한다.</p>
<p>선택자별 예시</p>
<pre><code>    1) tag
    soup.select(&#39;tag&#39;)  
        예시)
        soup.select(&#39;div&#39;) → 모든 &lt;div&gt; 태그를 찾아서 반환

    2) .class
        예시)
        soup.select(&#39;.title&#39;) → class=&quot;title&quot;인 모든 요소를 찾아서 반환

    3) #id
        예시)
        soup.select(&#39;#header&#39;) → id=&quot;header&quot;인 모든 요소를 찾아서 반환

    4) tag.class
        예시)
        soup.select(&#39;p.warning&#39;) → &lt;p class=&quot;warning&quot;&gt;인 모든 요소를 찾아서 반환

    5) 부모태그 &gt; 자식태그
        예시)
        soup.select(&#39;div &gt; span&#39;) → &lt;div&gt; 안에 &lt;span&gt;인 모든 요소를 찾아서 반환

    6)[attr]
        예시)
        soup.select(&#39;[href]&#39;) → href 속성이 있는 모든 요소 찾아서 반환

    7) [attr=&quot;value&quot;]
        예시)
        soup.select(&#39;[type=&quot;text&quot;]&#39;) → 속성 = 값 인 모든 요소를 찾아서 반환

    8) [attr^=&quot;value&quot;]
        예시)
        soup.select(&#39;[class^=&quot;btn&quot;]&#39;) → 속성 값이 ~로 시작하는 모든 요소를 찾아서 반환

    9) [attr$=&quot;value&quot;]
        예시)
        soup.select(&#39;[href$=&quot;.pdf&quot;]&#39;) → 속성 값이 ~로 끝나는 모든 요소를 찾아서 반환

    10) [attr*=&quot;value&quot;]
        예시)
        soup.select(&#39;[class*=&quot;active&quot;]&#39;) → 속성 값에 ~ 포함하는 모든 요소를 찾아서 반환</code></pre><pre><code># HTML을 분석(파싱)하기 위한 라이브러리
from bs4 import BeautifulSoup

# 파일 경로 지정. 현재 폴더 기준(./)
file_path = &#39;./html_css/historyofpython.html&#39;

# HTML 파일 열기
# &#39;r&#39; → 읽기 모드
# encoding=&#39;utf-8&#39; → 한글 깨짐 방지
# f.read() → 파일 전체 내용을 문자열로 읽음
with open(file_path, &#39;r&#39;, encoding=&#39;utf-8&#39;) as f:
    html_doc = f.read()

# HTML 코드 전체가 들어있는 문자열(str)
type(html_doc)
# html_doc

# head 부분 제거
body = html_doc.split(&#39;&lt;/head&gt;&#39;)[1]
response = BeautifulSoup(body, &#39;html.parser&#39;)
response

# BeautifulSoup을 이용해서 파싱하였으므로 bs4.BeautifulSoup 타입
type(response)</code></pre><h2 id="selenium">selenium</h2>
<h3 id="동적-로딩-문제-javascript-rendering-문제">동적 로딩 문제 (JavaScript Rendering 문제)</h3>
<pre><code>import requests
url = &quot;https://finance.naver.com/sise/lastsearch2.naver&quot;
response = requests.get(url)
response

headers = {
    &quot;User-Agent&quot;: &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36&quot;,
    &quot;Accept-Language&quot;: &quot;ko-KR,ko;q=0.9,en;q=0.8&quot;,
    &quot;Referer&quot;: &quot;https://finance.naver.com/&quot;
}
response = requests.get(url, headers = headers)
response

soup = BeautifulSoup(response.text, &#39;html.parser&#39;)
soup.select(&#39;tbody &gt; tr&#39;)
soup.select(&#39;tbody&#39;)</code></pre><blockquote>
<p>결과로 빈 list 반환됨</p>
</blockquote>
<ol>
<li>정적 초기 로드 (Static Load)</li>
</ol>
<ul>
<li>requests.get()이 가져오는 부분</li>
<li>서버가 처음 보내주는 기본 HTML 문서</li>
<li>기본적인 HTML 구조, CSS 파일 연결 정보, JavaScript 파일을 불러오라는 <script> 태그 포함</li>
</ul>
<p>👉 실제 데이터가 아닌 데이터를 가져올 준비만 된 상태의 뼈대 HTML</p>
<ol start="2">
<li>동적 렌더링 (Dynamic Rendering)</li>
</ol>
<ul>
<li>브라우저에서만 발생</li>
<li>브라우저가 JavaScript 파일을 실행</li>
<li>JavaScript가 서버에 추가 요청(AJAX, fetch 등)을 보냄</li>
<li>서버에서 받은 데이터를 이용해 HTML을 새로 생성하거나 기존 HTML을 수정</li>
<li>화면에 데이터를 동적으로 삽입</li>
</ul>
<p>👉 결과로 우리가 눈으로 보는 최종 화면 얻음</p>
<p>❗ requests.get()은 JavaScript를 실행하지 않고 HTML 파일만 가져오므로 response.text에는 자바스크립트 실행 전의 초기 HTML만 들어 있음
실제 데이터는 브라우저가 JS를 실행해야 생성되기 때문에
requests만으로는 보이지 않는 것.</p>
<h4 id="동적-로딩-페이지-크롤링">동적 로딩 페이지 크롤링</h4>
<ol>
<li>Selenium 사용(브라우저 자동화, JS 실행 가능)</li>
<li>네트워크 탭에서 실제 데이터 API 직접 호출</li>
<li>개발자 도구에서 AJAX 요청 URL 분석 후 직접 requests로 요청</li>
</ol>
<blockquote>
<p>requests는 자바스크립트를 실행하지 않기 때문에, 동적으로 생성되는 데이터는 가져오지 못한다.</p>
</blockquote>
<pre><code># pip install selenium
!pip install selenium

from selenium import webdriver
url = &quot;https://finance.naver.com/sise/lastsearch2.naver&quot;

driver = webdriver.Chrome() # 또는 Firefox, Edge 등
driver.get(url)

# 페이지 로딩 시간을 충분히 줍니다.
driver.implicitly_wait(10) 

# 자바스크립트가 실행된 최종 HTML 소스를 가져옵니다.
final_html = driver.page_source

# BeautifulSoup으로 분석
soup = BeautifulSoup(final_html, &#39;html.parser&#39;)

driver.quit()

# soup.select(&#39;tbody &gt; tr&#39;)
# BeautifulSoup을 이용해 테이블의 tbody 안에 있는 모든 tr(행)을 선택한다.
# 즉, 네이버 금융 인기검색 종목 표의 각 종목 행을 가져오는 코드.</code></pre><h3 id="실습">실습</h3>
<p><a href="https://finance.naver.com/sise/lastsearch2.naver">https://finance.naver.com/sise/lastsearch2.naver</a> 페이지에서</p>
<ol>
<li>데이터를 크롤링하고</li>
<li>데이터프레임으로 만든 후</li>
<li>excel 파일로 저장하시오</li>
</ol>
<pre><code># pip install selenium
!pip install selenium

# pip install requests beautifulsoup4
!pip install requests beautifulsoup4

from selenium import webdriver
from bs4 import BeautifulSoup
import pandas as pd

url = &quot;https://finance.naver.com/sise/lastsearch2.naver&quot;

driver = webdriver.Chrome() # 또는 Firefox, Edge 등
driver.get(url)

# 페이지 로딩 시간을 충분히 줍니다.
driver.implicitly_wait(10) 

# 자바스크립트가 실행된 최종 HTML 소스를 가져옵니다.
final_html = driver.page_source

# BeautifulSoup으로 분석
soup = BeautifulSoup(final_html, &#39;html.parser&#39;)

# BeautifulSoup을 이용해 테이블의 tbody 안에 있는 모든 tr(행)을 선택한다.
# soup.select(&#39;tbody &gt; tr&#39;)

header_row = soup.select_one(&#39;tr.type1&#39;)
headers = [th.get_text(strip=True) for th in header_row.find_all(&#39;th&#39;)]

print(headers)

# driver.quit()

rows = soup.select(&#39;tbody &gt; tr&#39;)

data = []

for row in rows:
    no_cell = row.select_one(&#39;td.no&#39;)

    if no_cell:   # 순위가 있는 행만
        cols = row.find_all(&#39;td&#39;)
        row_data = [col.get_text(strip=True) for col in cols]
        data.append(row_data)

print(data[:2])

# 자동으로 행 인덱스 생성
df = pd.DataFrame(data, columns=headers)

print(df)

df.to_excel(&quot;naver_finance.xlsx&quot;, index=False, engine=&#39;openpyxl&#39;)</code></pre><p>엑셀 저장할 때 행 제거하고 싶은 경우</p>
<p>```
df.to_excel("naver.xlsx", index=False)
``</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[미니프로젝트 DAY2(2)]]></title>
            <link>https://velog.io/@aiden_lee/%EB%AF%B8%EB%8B%88%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-DAY22</link>
            <guid>https://velog.io/@aiden_lee/%EB%AF%B8%EB%8B%88%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-DAY22</guid>
            <pubDate>Sat, 06 Dec 2025 05:25:35 GMT</pubDate>
            <description><![CDATA[<h2 id="csrf-취약점">CSRF 취약점</h2>
<h3 id="csrf-차단-코드">CSRF 차단 코드</h3>
<h4 id="기본-아이디어">기본 아이디어</h4>
<p>서버(app.py)</p>
<ul>
<li>세션에 csrf_token을 하나 만들어 둔다.</li>
<li>모든 POST/PUT/DELETE 요청이 들어올 때, 요청 안에 실린 토큰이 세션에 저장된 값이랑 같은지 체크</li>
<li>다른 경우 공격으로 보고 400 에러 발생</li>
</ul>
<p>템플릿(HTML)</p>
<ul>
<li><code>&lt;form method=&quot;post&quot;&gt;</code>마다 <code>&lt;input type=&quot;hidden&quot; name=&quot;csrf_token&quot; value=&quot;{{ csrf_token() }}&quot;&gt;</code>
토큰을 함께 보낸다.</li>
</ul>
<p>→ 상품삭제, 회원탈퇴, 글수정, 채팅 전송 등 모든 상태 변경 요청이 CSRF 보호를 받게 됨.</p>
<h4 id="코드-작성">코드 작성</h4>
<ol>
<li><p>import 추가</p>
<p>app.py 맨 위쪽 import 아랫부분에 추가</p>
<pre><code>import secrets
from flask import abort</code></pre></li>
<li><p>CSRF 토큰 생성 &amp; 템플릿에서 사용</p>
<p>app = Flask(<strong>name</strong>) 아래 설정(config) 직후에 추가</p>
<pre><code># ---------------- CSRF 공통 설정 ----------------

def generate_csrf_token():
   &quot;&quot;&quot;세션에 csrf_token이 없으면 하나 생성해서 돌려주는 함수&quot;&quot;&quot;
   token = session.get(&quot;csrf_token&quot;)
   if not token:
       token = secrets.token_hex(32)  # 64자리 정도의 랜덤 문자열
       session[&quot;csrf_token&quot;] = token
   return token

@app.context_processor
def inject_csrf_token():
   &quot;&quot;&quot;모든 템플릿에서 csrf_token() 을 쓸 수 있게 주입&quot;&quot;&quot;
   return dict(csrf_token=generate_csrf_token)</code></pre></li>
<li><p>미들웨어(before_request)로 전체 요청 검사</p>
<p>위 코드의 바로 아래에 모든 POST/PUT/PATCH/DELETE 요청이 들어올 때 CSRF 토큰을 검사하는 코드를 추가</p>
<pre><code># CSRF 검사용 예외 경로 (원하면 조절 가능)
CSRF_EXEMPT_ENDPOINTS = {
   &#39;health&#39;,        # /health 같은 단순 체크용
   # &#39;some_api&#39;     # 필요하면 여기 추가
}

@app.before_request
def csrf_protect():
   # GET, HEAD, OPTIONS, TRACE 는 안전한 메서드로 보고 검사 안 함
   if request.method in (&quot;GET&quot;, &quot;HEAD&quot;, &quot;OPTIONS&quot;, &quot;TRACE&quot;):
       return

   # health 같은 것 제외하고 검사
   if request.endpoint in CSRF_EXEMPT_ENDPOINTS:
       return

   session_token = session.get(&quot;csrf_token&quot;)

   # JSON 요청인지, 일반 form인지에 따라 토큰 위치가 다를 수 있음
   form_token = request.form.get(&quot;csrf_token&quot;)  # 일반 form
   header_token = request.headers.get(&quot;X-CSRFToken&quot;) or request.headers.get(&quot;X-CSRF-Token&quot;)

   token = form_token or header_token

   if not session_token or not token or not secrets.compare_digest(str(session_token), str(token)):
       # 로그 찍고 차단
       print(&quot;[CSRF BLOCKED] method=&quot;, request.method, &quot;path=&quot;, request.path, 
             &quot;form_token=&quot;, form_token, &quot;header_token=&quot;, header_token)
       abort(400, description=&quot;CSRF token missing or invalid&quot;)
</code></pre><p>→ 이제부터는 로그인, 글 작성 등 모든 POST 계열 요청이 반드시 CSRF 토큰을 포함해야 통과됨.</p>
</li>
</ol>
<ol start="4">
<li><p>템플릿에 토큰 추가(폼 전체에 적용)</p>
<p>상품 등록, 상품 수정, 상품 삭제 form, 회원가입, 로그인 등 POST를 사용하는 모든 폼에 다음과 같이 코드 한 줄을 추가.</p>
<pre><code>&lt;form method=&quot;POST&quot; ...&gt;
   &lt;input type=&quot;hidden&quot; name=&quot;csrf_token&quot; value=&quot;{{ csrf_token() }}&quot;&gt;
   ...
&lt;/form&gt;</code></pre><p>product_new.html:</p>
<pre><code>&lt;form method=&quot;POST&quot; enctype=&quot;multipart/form-data&quot;&gt;
   &lt;input type=&quot;hidden&quot; name=&quot;csrf_token&quot; value=&quot;{{ csrf_token() }}&quot;&gt;
   &lt;!-- 나머지 input들 --&gt;
&lt;/form&gt;</code></pre><p>product_edit.html:</p>
<pre><code>&lt;form method=&quot;POST&quot; enctype=&quot;multipart/form-data&quot;&gt;
   &lt;input type=&quot;hidden&quot; name=&quot;csrf_token&quot; value=&quot;{{ csrf_token() }}&quot;&gt;
   ...
&lt;/form&gt;</code></pre><p>product_detail.html(상품 삭제 form):</p>
<pre><code>&lt;form action=&quot;/products/{{ product.id }}/delete&quot; method=&quot;POST&quot; 
     onsubmit=&quot;return confirm(&#39;정말로 이 상품을 삭제하시겠습니까?&#39;);&quot; style=&quot;margin-top: 0;&quot;&gt;
   &lt;input type=&quot;hidden&quot; name=&quot;csrf_token&quot; value=&quot;{{ csrf_token() }}&quot;&gt;
   &lt;button type=&quot;submit&quot; class=&quot;contact-btn&quot; ...&gt;
       🗑️ 상품 삭제하기
   &lt;/button&gt;
&lt;/form&gt;</code></pre><p>회원가입/로그인 폼에도 똑같이 한 줄 추가</p>
</li>
</ol>
<p>4번 절차까지 완료하면 아까까지 잘 들어가졌던 공격 html 접속 시 다음과 같은 400 Bad Request 에러가 발생함
<img src="https://velog.velcdn.com/images/aiden_lee/post/c0b0a659-4e4e-4dbc-8008-d65af8b23310/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[미니프로젝트 DAY2(1)]]></title>
            <link>https://velog.io/@aiden_lee/%EB%AF%B8%EB%8B%88%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-DAY21</link>
            <guid>https://velog.io/@aiden_lee/%EB%AF%B8%EB%8B%88%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-DAY21</guid>
            <pubDate>Sat, 06 Dec 2025 04:25:13 GMT</pubDate>
            <description><![CDATA[<h2 id="csrf-취약점">CSRF 취약점</h2>
<h3 id="csrfcross-site-request-forgery-사이트-간-요청-위조">CSRF(Cross-Site Request Forgery, 사이트 간 요청 위조)</h3>
<p>사용자가 의도하지 않은 요청이 사용자의 권한으로 서버에 전달되도록 속이는 공격.</p>
<p>정상적으로 사이트에 로그인한 상태의 피해자가 공격자가 생성한 악의적 웹페이지 또는 링크에 접속하면, 브라우저는 쿠키를 자동으로 첨부하기 때문에 공격자의 요청을 정상 사용자 요청으로 착각한다.</p>
<p>❗전제 조건은 피해자가 <strong>로그인 된 상태</strong>에서 악의적 링크/웹페이지에 접속하는 것</p>
<h4 id="csrf가-왜-발생할까">CSRF가 왜 발생할까?</h4>
<p><strong>→ 브라우저가 쿠키를 자동으로 전송하기 때문</strong></p>
<p>시나리오</p>
<blockquote>
<p>사용자가 A사이트에 로그인하면 세션 쿠키가 저장됨. 그 후 공격자가 만든 페이지를 클릭하면, 브라우저는 자동으로 A.com 쿠키를 첨부한다. 따라서 서버는 “정상 사용자 요청”이라고 믿고 계정 변경, 게시글 삭제, 송금 요청 등이 실행된다.</p>
</blockquote>
<p><strong>→ 서버가 “요청이 진짜 사용자가 보낸 것인지” 확인하지 않음</strong></p>
<p>즉, CSRF Token이 없거나 검증하지 않을 때 공격 성공.</p>
<h3 id="csrf-공격-예제">CSRF 공격 예제</h3>
<p>내 웹사이트는 CSRF 취약점이 있을까?
간단 테스트:</p>
<p>다음과 같은 내용의 html 파일을 생성한다.</p>
<pre><code>&lt;form action=&quot;https://site.com/products/1/delete&quot; method=&quot;POST&quot;&gt;&lt;/form&gt;
&lt;script&gt;document.forms[0].submit()&lt;/script&gt;</code></pre><p>site명과 게시글의 number, 요청 내용은 필요에 따라 조작한다.</p>
<p>사이트에 로그인한 상태로 html 파일을 클릭하였을 때 게시글이 삭제되면 CSRF에 대해 취약한 것으로 판단할 수 있다.</p>
<p>CSRF는 다음과 같이 다양한 공격에 적용될 수 있다.</p>
<table>
<thead>
<tr>
<th>기능</th>
<th>위험도</th>
</tr>
</thead>
<tbody><tr>
<td>비밀번호 변경</td>
<td>매우 높음</td>
</tr>
<tr>
<td>계정 삭제</td>
<td>매우 높음</td>
</tr>
<tr>
<td>송금/결제</td>
<td>치명적</td>
</tr>
<tr>
<td>게시물 수정/삭제</td>
<td>높음</td>
</tr>
<tr>
<td>상품 등록/삭제</td>
<td>높음</td>
</tr>
<tr>
<td>좋아요/댓글 조작</td>
<td>중간</td>
</tr>
</tbody></table>
<h3 id="csrf-취약점-진단">CSRF 취약점 진단</h3>
<ol>
<li><p>POST 요청에 CSRF Token이 있는가?
 →없으면 취약 가능성이 높다
 있어도 서버에서 검증하지 않으면 취약</p>
</li>
<li><p>Referer / Origin 체크를 하는가?
 →없으면 위험</p>
</li>
<li><p>쿠키 SameSite 설정이 적절한가?
 SameSite=Lax → 대부분의 CSRF 자동으로 막힘
 SameSite=None; Secure → 외부에서 쿠키 전송 가능하므로 취약</p>
</li>
<li><p>민감 요청이 GET 방식인가?(예:GET /delete?id=1)
 →GET으로 삭제/변경이 가능한 경우 CSRF 취약</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[생성형 AI 활용한 보안 프로그래밍 기술 - DAY3(2)]]></title>
            <link>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY32</link>
            <guid>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY32</guid>
            <pubDate>Fri, 28 Nov 2025 08:06:24 GMT</pubDate>
            <description><![CDATA[<h2 id="port-scanner">Port Scanner</h2>
<h3 id="소켓">소켓</h3>
<p>네트워크에서 데이터를 주고받기 위한 통신 통로.
네트워크 통신용 인터페이스로, 프로그램이 네트워크로 데이터를 주고받기 위해 OS에 요청할 수 있는 표준화된 통신 엔드포인트(endpoint)이다.</p>
<p>운영체제는 네트워크 프로토콜(TCP/IP 등)을 직접 제어하게 하지 않는다. 대신 소켓이라는 표준 인터페이스를 제공해서 프로그램이 다음을 요청할 수 있게 한다.</p>
<ul>
<li>TCP 연결 요청 (connect())</li>
<li>서버 소켓 대기 (bind(), listen())</li>
<li>연결 수락 (accept())</li>
<li>데이터 송·수신 (send(), recv())</li>
<li>연결 종료 (close())</li>
</ul>
<p>즉, 네트워크 통신의 모든 동작은 소켓을 통해서만 이루어지며 다음과 같은 구조로 동작한다.</p>
<p>프로그램 → 소켓 API → OS → 네트워크 스택(TCP/IP) → 외부 네트워크</p>
<h4 id="파이썬에서-소켓-사용">파이썬에서 소켓 사용</h4>
<pre><code>import socket

# 소켓 생성
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# AF_INET: IPv4 주소 사용
# SOCK_STREAM: TCP 소켓 (연결 지향형)</code></pre><p><code>socket.socket()</code>은 OS의 소켓 시스템 호출을 감싸는 함수다.
운영체제에게 네트워크 통신용 소켓을 하나 생성하라고 요청하는 것이다.</p>
<pre><code>socket.socket(address_family, socket_type)</code></pre><ol>
<li><p>address_family</p>
<p> 네트워크 프로토콜의 주소 체계를 지정한다.   </p>
</li>
</ol>
<table>
<thead>
<tr>
<th>값</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>AF_INET</code></td>
<td>IPv4 주소 체계 사용</td>
</tr>
<tr>
<td><code>AF_INET6</code></td>
<td>IPv6 주소 체계 사용</td>
</tr>
</tbody></table>
<ol start="2">
<li><p>socket_type</p>
<p> 전송 계층 프로토콜을 선택한다.</p>
</li>
</ol>
<table>
<thead>
<tr>
<th>값</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>SOCK_STREAM</code></td>
<td>TCP 사용 (연결형, 신뢰 전송)</td>
</tr>
<tr>
<td><code>SOCK_DGRAM</code></td>
<td>UDP 사용 (비연결형, 비신뢰 전송)</td>
</tr>
</tbody></table>
<h3 id="포트">포트</h3>
<p>포트 번호란 IP 주소와 함께 사용되는 가상 통신 주소이다. 0부터 65535까지의 숫자로 이루어지며, 웹 서버(포트 80)나 보안 웹(포트 443)처럼 특정 서비스에 할당된 번호와 사용자가 임의로 사용할 수 있는 동적 포트 등으로 나뉜다.</p>
<h4 id="포트-상태">포트 상태</h4>
<ul>
<li>Open (열림) - 해당 포트 번호를 이미 어떤 프로세스가 listen() 중이다. 즉, TCP 서버가 대기 중</li>
<li>Closed (닫힘) - 해당 포트는 존재하지만 서비스가 아무것도 bind() 하지 않음. 즉, OS가 이 포트를 사용 중인 프로세스를 갖고 있지 않다.</li>
<li>Filtered (필터링됨) - TCP 요청이 방화벽/라우터/보안 장비에 의해 차단되었다. 즉, 패킷이 목적지 포트의 운영체제까지 도달하지 못함.</li>
</ul>
<table>
<thead>
<tr>
<th>상태</th>
<th>트래픽 흐름</th>
<th>TCP 응답</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Open</strong></td>
<td>SYN → 서버 도착</td>
<td>SYN/ACK</td>
<td>서버 프로세스가 해당 포트에서 LISTEN 중</td>
</tr>
<tr>
<td><strong>Closed</strong></td>
<td>SYN → 서버 도착</td>
<td>RST/ACK</td>
<td>해당 포트를 사용하는 프로세스 없음</td>
</tr>
<tr>
<td><strong>Filtered</strong></td>
<td>SYN → 방화벽에서 차단</td>
<td>응답 없음 또는 ICMP</td>
<td>패킷이 OS까지 도달하지 못함</td>
</tr>
</tbody></table>
<h3 id="포트-스캔">포트 스캔</h3>
<p>특정 컴퓨터의 어떤 포트가 열려있는지 확인하는 과정</p>
<p>즉, 네트워크 장비(서버, PC 등)의 각 포트 번호에 대해 연결을 시도하거나 특정 패킷을 보내고 그 응답을 분석해서 해당 포트가 실제로 서비스 중인지, 차단됐는지, 비어 있는지를 알아내는 작업이다.</p>
<p><strong>❗왜 포트 스캔을 하는가</strong></p>
<ul>
<li>어떤 서비스가 실행 중인지 확인</li>
<li>취약점 탐지 - 열려있는 서비스의 취약점을 공격</li>
</ul>
<h2 id="keylogger">KeyLogger</h2>
<p>사용자가 키보드로 입력하는 내용을 기록하는 프로그램.
해킹, 악성코드, 모의해킹, 디버깅 등 다양한 목적에 사용된다.</p>
<h2 id="ransomware">Ransomware</h2>
<h3 id="암호화encryption">암호화(Encryption)</h3>
<p>정보를 읽을 수 없는 형태로 변환하는 것.</p>
<h4 id="암호화의-목적">암호화의 목적</h4>
<ul>
<li><p>기밀성 (Confidentiality) - 중요한 정보를 다른 사람이 읽지 못해야 함</p>
</li>
<li><p>무결성 (Integrity) - 정보가 변경되지 않아야 함</p>
</li>
<li><p>인증 (Authentication) - 정보의 출처 확인</p>
</li>
</ul>
<h4 id="암호화의-핵심-요소">암호화의 핵심 요소</h4>
<ul>
<li><p>평문 (Plaintext) - 암호화하기 전의 원본 데이터</p>
</li>
<li><p>암호문 (Ciphertext) - 암호화한 후의 데이터. 읽을 수 없는 형태</p>
</li>
<li><p>암호화 키 (Encryption Key) - 암호화와 복호화에 사용하는 데이터. 키 없이 복호화 불가</p>
</li>
<li><p>암호화 알고리즘 - 암호화를 수행하는 방법(예: XOR, AES, RSA)</p>
</li>
</ul>
<h4 id="암호화-방식의-종류">암호화 방식의 종류</h4>
<ol>
<li><p>대칭키 암호화 (Symmetric Encryption)
암호화 키 = 복호화 키
암호화와 복호화 수행 시 동일한 키를 사용
예: XOR, AES
장점: 빠름
단점: 키를 안전하게 전달해야 함</p>
</li>
<li><p>비대칭키 암호화 (Asymmetric Encryption)
암호화 키 ≠ 복호화 키
공개키와 개인키 쌍 사용
예: RSA
장점: 키 전달이 안전함
단점: 느림</p>
</li>
</ol>
<table>
<thead>
<tr>
<th>구분</th>
<th>암호화 키</th>
<th>설명</th>
<th>예</th>
<th>장점</th>
<th>단점</th>
</tr>
</thead>
<tbody><tr>
<td>대칭키 암호화 (Symmetric Encryption)</td>
<td>암호화 키 = 복호화 키</td>
<td>암호화와 복호화 수행 시 동일한 키를 사용</td>
<td>XOR, AES</td>
<td>빠름</td>
<td>키를 안전하게 전달해야 함</td>
</tr>
<tr>
<td>비대칭키 암호화 (Asymmetric Encryption)</td>
<td>암호화 키 ≠ 복호화 키</td>
<td>공개키와 개인키 쌍 사용</td>
<td>RSA</td>
<td>키 전달이 안전함</td>
<td>느림</td>
</tr>
</tbody></table>
<h4 id="xor-연산">XOR 연산</h4>
<ul>
<li><p>자기 역원 - A XOR B XOR B = A</p>
</li>
<li><p>암호화와 복호화가 동일
  암호화: 평문 XOR 키 = 암호문
복호화: 암호문 XOR 키 = 평문</p>
</li>
</ul>
<blockquote>
<p>평문: 5
키:   3
.
암호화:
5 XOR 3 = 6  (이진수: 101 XOR 011 = 110)
.
복호화:
6 XOR 3 = 5  (이진수: 110 XOR 011 = 101)</p>
</blockquote>
<blockquote>
<p>평문: &quot;A&quot;
키: &quot;K&quot;
문자 &quot;A&quot;의 ASCII 코드: 65 (이진수: 01000001)
키 &quot;K&quot;의 ASCII 코드:  75 (이진수: 01001011)
.
암호화:
  01000001  (A)
X 01001011  (K)
───────────
  00001010  (결과: 10)
.
복호화:
  00001010  (암호문)
X 01001011  (K)
───────────
  01000001  (A - 원본 복구)</p>
</blockquote>
<p>❗키가 짧은 경우</p>
<blockquote>
<p>평문: &quot;Hello&quot; (5바이트)
키:   &quot;AB&quot; (2바이트)
.
평문: H  e  l  l  o
키:   A  B  A  B  A  (키를 반복하여 확장)
.
H XOR A = 암호문[0]
e XOR B = 암호문[1]
l XOR A = 암호문[2]
l XOR B = 암호문[3]
o XOR A = 암호문[4]</p>
</blockquote>
<h3 id="파일-암호화">파일 암호화</h3>
<p>파일 암호화의 절차</p>
<ol>
<li><p>파일 읽기 - 파일을 바이트(byte) 형태로 읽어옴</p>
</li>
<li><p>암호화 키 생성 - 암호화에 사용할 키 생성</p>
</li>
<li><p>XOR 연산 수행 - 파일 데이터와 키를 XOR 연산</p>
</li>
<li><p>암호화된 데이터 저장 - 암호화된 바이트를 파일에 저장</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[도커, 쿠버네티스, 젠킨스]]></title>
            <link>https://velog.io/@aiden_lee/%EB%8F%84%EC%BB%A4-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-%EC%A0%A0%ED%82%A8%EC%8A%A4</link>
            <guid>https://velog.io/@aiden_lee/%EB%8F%84%EC%BB%A4-%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-%EC%A0%A0%ED%82%A8%EC%8A%A4</guid>
            <pubDate>Fri, 28 Nov 2025 05:12:50 GMT</pubDate>
            <description><![CDATA[<p>도커(Docker), 쿠버네티스(Kubernetes), 젠킨스(Jenkins)는 모두 소프트웨어 개발 및 배포에 사용되는 도구이다.</p>
<p>각각 다음과 같은 역할을 한다.</p>
<ol>
<li><p><strong>도커(Docker)</strong>: 컨테이너 기반의 애플리케이션 배포를 가능하게 하는 도구이다. 컨테이너는 애플리케이션과 그것을 실행하는 데 필요한 모든 의존성을 포함하기 때문에 도커를 사용하면 개발 환경과 운영 환경 간의 차이를 최소화할 수 있다.</p>
</li>
<li><p><strong>쿠버네티스(Kubernetes)</strong>: 컨테이너화 된 애플리케이션의 배포, 스케일링 및 관리를 자동화하는 오픈소스 플랫폼이다. 쿠버네티스를 사용하면 수백, 수천 개의 컨테이너를 효과적으로 관리하고 조정할 수 있다.</p>
</li>
<li><p><strong>젠킨스(Jenkins)</strong>: 지속적인 통합(Continuous Integration) 및 지속적인 배포(Continuous Deployment)를 지원하는 도구이다. 즉, 개발자가 코드를 변경하면 젠킨스는 이를 자동으로 빌드하고, 테스트하고, 프로덕션 환경에 배포한다.</p>
</li>
</ol>
<p>세 도구는 서로 연관되어 작동한다.</p>
<ul>
<li><p>도커를 사용해 애플리케이션을 컨테이너화하면, 이 컨테이너는 어디에서든 동일하게 실행되기 때문에 개발, 테스트, 프로덕션 환경 간의 차이를 제거할 수 있다.</p>
</li>
<li><p>젠킨스는 개발자가 코드를 변경하면 자동으로 이 코드를 빌드하고, 이를 도커 컨테이너로 패키지화하여 테스트하고 배포한다.</p>
</li>
<li><p>쿠버네티스는 이렇게 배포된 컨테이너를 클러스터 환경에서 관리한다. 쿠버네티스는 컨테이너를 적절한 위치에 스케줄링하고, 애플리케이션의 상태를 모니터링하고, 필요에 따라 컨테이너를 스케일링하거나 롤백하는 등의 작업을 수행한다.</p>
</li>
</ul>
<p>따라서 도커, 쿠버네티스, 젠킨스는 각각 애플리케이션의 컨테이너화, 클러스터 관리, 지속적인 통합 및 지속적인 배포를 담당하며, 함께 사용될 때 효과적인 DevOps 파이프라인을 구성하는 핵심 요소가 된다.</p>
<p>도커, 쿠버네티스, 젠킨스는 DevOps 파이프라인 도구라고 볼 수 있다.</p>
<p>개발부터 테스트, 배포, 운영에 이르는 소프트웨어 개발 생명주기 전반을 자동화하고 효율화하는데 중요한 역할을 한다.</p>
<ul>
<li>도커는 애플리케이션과 그 실행 환경을 컨테이너라는 격리된 환경으로 패키지화하는 기능을 제공한다.</li>
<li>젠킨스는 소스 코드의 변경을 감지하여 자동으로 빌드, 테스트, 배포하는 지속적인 통합(CI) 및 지속적인 배포(CD)를 지원한다.</li>
<li>쿠버네티스는 이렇게 생성된 컨테이너들을 대규모로 관리하고, 서비스를 유지하면서 스케일링하고, 장애가 발생했을 때 복구하는 등의 역할을 한다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[SpringBoot:Annotation]]></title>
            <link>https://velog.io/@aiden_lee/SpringBootAnnotation</link>
            <guid>https://velog.io/@aiden_lee/SpringBootAnnotation</guid>
            <pubDate>Fri, 28 Nov 2025 05:05:24 GMT</pubDate>
            <description><![CDATA[<p>@Controller : 컨트롤러임을 표기</p>
<p>@GettMapping : 이러한 요청을 받으면 다음을 실행하라.
//Get 요청</p>
<p>@ResponseBody : 이 함수의 리턴값을 브라우저에 전송하라.
//없으면 리턴값이 클라이언트에 보여지지 않음.
//리턴값이 있어야 함.</p>
<p>@AllArgsConstructor : 모든 arguments를 생성자로 받음. 즉, 클래스의 필드가 5개 존재하는 경우 모든 5개의 필드를 인자로 받는 생성자가 자동 생성됨.</p>
<p>@Getter : 클래스 내 모든 필드에 대해 getter 생성</p>
<p>@Component : 한 번만 생성되어 재사용 됨. 즉, 공유 객체임을 표시 //클래스에 @Component 붙이면 자동으로 Bean이 됨.
@Repository
@Service</p>
<p>@Autowired : @Autowired를 붙이면 new를 통해 객체를 생성할 필요 없다. 필드에 붙이면 필드 주입, 생성자에 붙이면 생성자 주입. 생성자가 하나인 클래스의 경우 생략 가능.
필드 주입 시 final 키워드 붙일 수 없음.</p>
<p>@RequiredArgsConstructor : 생성자 주입. final 붙은 필드를 초기화하는 생성자를 자동으로 생성해준다. 따라서 @RequiredArgsConstructor를 붙인 경우 생성자 생략 가능.</p>
<p>@ApplicationScope : 수명 김. 애플리케이션 전체에 걸쳐 존재함.
@RequestScope : 수명 짧음. 매번 만들어졌다 사라짐.</p>
<p>@Data : @Getter, @Setter 대신 사용</p>
<p>@Validate
@Valid</p>
<p>@NotBlank</p>
<p>@PathVariable</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[생성형 AI 활용한 보안 프로그래밍 기술 - DAY4(1)]]></title>
            <link>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY41</link>
            <guid>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY41</guid>
            <pubDate>Fri, 28 Nov 2025 04:48:05 GMT</pubDate>
            <description><![CDATA[<h2 id="docker">Docker</h2>
<h3 id="설치">설치</h3>
<p>Windows 10 Home 버전을 사용하고 있기 때문에, Hyper-V가 없는 상황이었다. 따라서 WSL2를 설치한 뒤 Docker를 사용했다.</p>
<p>powerShell을 관리자로 실행해 wsl 설정을 해준다.</p>
<pre><code># wsl 업데이트
PS C:\WINDOWS\system32&gt; wsl --update
업데이트 확인 중입니다.
Linux용 Windows 하위 시스템 최신 버전이 이미 설치되어 있습니다.

# wsl 버전확인
# wsl --status
PS C:\WINDOWS\system32&gt; wsl --status
기본 버전: 2

# 버전이 2가 아닌 경우
# wsl --set-default-version 2
PS C:\WINDOWS\system32&gt; wsl --set-default-version 2

# Windows 하위 시스템 활성화
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

# 가상머신 설정
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart</code></pre><h3 id="실행">실행</h3>
<p>Docker Compose 실행</p>
<ul>
<li>Docker Desktop 설치 및 실행</li>
<li>Windows에서 Docker Desktop이 실행 중인지 확인 필요</li>
</ul>
<ol>
<li><p>PowerShell을 관리자 버전으로 실행</p>
</li>
<li><p>프로젝트 디렉토리로 이동</p>
<pre><code> cd C:\Users\...\...</code></pre></li>
<li><p>Docker Compose로 서비스 시작</p>
<pre><code> # 백그라운드로 실행 (-d 옵션)
 docker-compose up -d</code></pre><pre><code> # 또는 로그를 보면서 실행 (첫 실행 시 권장)
 docker-compose up</code></pre></li>
<li><p>서비스 상태 확인</p>
<pre><code> # 실행 중인 컨테이너 확인
 docker-compose ps

 # 로그 확인
 docker-compose logs -f

 # 특정 서비스의 로그만 확인
 docker-compose logs -f web
 docker-compose logs -f mysql
 docker-compose logs -f nginx</code></pre></li>
<li><p>웹사이트 접속
 브라우저에서 <a href="http://localhost">http://localhost</a> 또는 <a href="http://127.0.0.1">http://127.0.0.1</a></p>
</li>
<li><p>서비스 중지/재시작</p>
<pre><code># 서비스 중지 (컨테이너는 유지)
docker-compose stop

# 서비스 재시작
docker-compose restart

# 서비스 중지 및 컨테이너 제거 (데이터는 유지)
docker-compose down

# 서비스 중지 및 모든 데이터 삭제 (주의!)
docker-compose down -v</code></pre></li>
<li><p>빌드 재실행 (코드 변경 후)</p>
<pre><code># 이미지 재빌드 후 시작
docker-compose up -d --build</code></pre></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[생성형 AI 활용한 보안 프로그래밍 기술 - DAY2(2)]]></title>
            <link>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY22</link>
            <guid>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY22</guid>
            <pubDate>Thu, 27 Nov 2025 00:34:55 GMT</pubDate>
            <description><![CDATA[<h2 id="파이썬">파이썬</h2>
<h3 id="파일-입출력">파일 입출력</h3>
<h4 id="text-파일">Text 파일</h4>
<p>open( )를 사용</p>
<blockquote>
<p>open(file 경로, mode, encoding=&#39;utf8&#39;)  </p>
</blockquote>
<p>mode</p>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/6991c8dd-4700-4e74-a905-9277d8c6e75c/image.png" alt=""></p>
<pre><code>#1. 파일 열기
filePath = &#39;file.txt&#39;
f = open(filePath, &#39;r&#39;, encoding=&#39;utf8&#39;)

while True:
    #2. 파일 내용 읽기
    content = f.read()

    #3. 파일 읽기 종료
    if content == &quot;&quot;:
        break
    print(content)

#4. 파일 닫기
f.close()</code></pre><p>with로 파일 닫기</p>
<blockquote>
<p>with open(file, mode, encoding) as f:</p>
</blockquote>
<pre><code># 1. 파일 열기. 읽기가 끝나면 자동으로 닫는다
with open(filePath,&quot;rt&quot;, encoding=&#39;utf-8&#39;) as f:
    # 2. 파일 읽기
    while True:
        c = f.read()
        if c == &#39;&#39;:
            break
        print(c, end=&#39;&#39;)</code></pre><p>readline( )</p>
<blockquote>
<p>readline() # 한 줄 읽기. 개행(\n)을 만날때까지 읽음. 문자열 반환</p>
</blockquote>
<blockquote>
<p>readline(int): 글자 수 만큼 읽음. 그 전에 개행(\n)을 만나면 읽기 종료</p>
</blockquote>
<h4 id="파일-및-디렉토리">파일 및 디렉토리</h4>
<p>파일 및 디렉토리 관리</p>
<table>
<thead>
<tr>
<th>함수</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>os.listdir(path)</code></td>
<td>지정한 <code>path</code> 내부의 파일과 폴더 목록을 리스트로 반환한다.</td>
</tr>
<tr>
<td><code>os.getcwd()</code></td>
<td>현재 작업 디렉터리(Current Working Directory)를 문자열로 반환한다.</td>
</tr>
<tr>
<td><code>os.chdir(path)</code></td>
<td>현재 작업 디렉터리를 <code>path</code>로 변경한다.</td>
</tr>
<tr>
<td><code>os.mkdir(path)</code></td>
<td><code>path</code> 위치에 새 디렉터리(폴더)를 생성한다.</td>
</tr>
<tr>
<td><code>os.rmdir(path)</code></td>
<td><code>path</code>에 있는 <strong>빈 디렉터리</strong>를 삭제한다. (내용 있으면 에러)</td>
</tr>
<tr>
<td><code>os.rename(src, dst)</code></td>
<td><code>src</code> 파일/폴더의 이름을 <code>dst</code>로 변경하거나 이동한다.</td>
</tr>
</tbody></table>
<p>경로 조작</p>
<table>
<thead>
<tr>
<th>함수</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>os.path.splitext(path)</code></td>
<td>파일 경로를 <code>(파일명, 확장자)</code> 튜플로 분리한다. 확장자는 <code>.txt</code> 같은 형태로 반환됨.</td>
</tr>
<tr>
<td><code>os.path.join(*paths)</code></td>
<td>여러 경로 요소를 OS에 맞는 형태로 결합하여 하나의 경로 문자열을 만든다.</td>
</tr>
<tr>
<td><code>os.path.split(path)</code></td>
<td>경로를 <code>(디렉터리 경로, 파일명)</code> 형태의 튜플로 분리한다.</td>
</tr>
</tbody></table>
<h4 id="csv파일">CSV파일</h4>
<blockquote>
<p>import csv</p>
</blockquote>
<table>
<thead>
<tr>
<th>함수</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>csv.reader(file)</code></td>
<td>CSV 파일을 <strong>리스트(list) 형태로 읽어오는 기본 리더</strong>. 한 줄을 리스트로 반환하며, 헤더 사용 여부는 직접 처리해야 한다.</td>
</tr>
<tr>
<td><code>csv.DictReader(file)</code></td>
<td>CSV 파일을 <strong>딕셔너리(dict) 형태로 읽어오는 리더</strong>. 첫 번째 행을 자동으로 헤더로 사용하여 <code>{헤더: 값}</code> 형태의 딕셔너리를 반환한다.</td>
</tr>
</tbody></table>
<p>pandas로 CSV 다루기</p>
<blockquote>
<p>pip install pandas # 설치
import pandas as pd # 불러오기</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[생성형 AI 활용한 보안 프로그래밍 기술 - DAY2(1)]]></title>
            <link>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY21</link>
            <guid>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY21</guid>
            <pubDate>Wed, 26 Nov 2025 07:22:22 GMT</pubDate>
            <description><![CDATA[<h2 id="파이썬">파이썬</h2>
<h3 id="문자열-뒤집기">문자열 뒤집기</h3>
<p>파이썬 슬라이싱을 이용해 문자열을 역순으로 뒤집기</p>
<blockquote>
<p>string[::-1] # 문자열 뒤집기</p>
</blockquote>
<p>슬라이싱의 기본 형태는 다음과 같다.</p>
<blockquote>
<p>seq[start : end : step]</p>
</blockquote>
<ul>
<li>start: 시작 인덱스</li>
<li>end: 끝 인덱스(해당 인덱스는 포함되지 않음)</li>
<li>step: 증가량(간격)</li>
</ul>
<p><code>step = -1</code>인 경우 거꾸로 이동한다.</p>
<p><strong>❗문자열, 리스트, 튜플 모두 사용 가능
모든 시퀀스 자료형에서 동작함</strong></p>
<h3 id="pass">pass</h3>
<p>파이썬에서, 아직 특별한 동작을 지정하지 않을 때 사용한다.
pass 처리한 부분은 어떠한 명령을 수행하지 않는다.</p>
<pre><code>if a &gt; 3:
    pass</code></pre><h3 id="예외처리">예외처리</h3>
<blockquote>
<p>try: 
    &emsp;실행할 코드
  except 에러명1:
    &emsp;에러처리 코드1
  except 에러명2:
    &emsp;에러처리 코드2
  else:
    &emsp;try 블록에 에러가 없을 경우 실행
  finally:
    &emsp;항상 실행</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[생성형 AI 활용한 보안 프로그래밍 기술 - DAY1(3)]]></title>
            <link>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY13</link>
            <guid>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY13</guid>
            <pubDate>Wed, 26 Nov 2025 02:24:26 GMT</pubDate>
            <description><![CDATA[<h2 id="파이썬">파이썬</h2>
<h3 id="포맷팅">포맷팅</h3>
<h4 id="c-스타일">C 스타일</h4>
<p>문자열에 변수의 값을 삽입하여 출력하고 싶은 경우, %s, %d, %f를 사용할 수 있다.</p>
<blockquote>
<p>%s: string
%d: decimal
%f: float</p>
</blockquote>
<pre><code>price = 100
print(&quot;가격은 %s원&quot; %price)</code></pre><blockquote>
<p>가격은 100원</p>
</blockquote>
<p>날짜 시간 포맷팅</p>
<blockquote>
<p>%Y: 연도
%m: 월(숫자)
%B: 월(문자)
%d: 일
%H: 시(24시간)
%I: 시(12시간)
%M: 분
%S: 초
%w: 요일(숫자, 일요일 = 0)
%A: 요일(문자)</p>
</blockquote>
<h4 id="연산자-">연산자 +</h4>
<p><code>str()</code>로 변환한 후 <code>+</code>를 이용해 문자열끼리 접합하면 된다.</p>
<pre><code>price = 100
print(&quot;가격은 &quot; + str(price) + &quot;원&quot;)</code></pre><blockquote>
<p>가격은 100원</p>
</blockquote>
<h4 id="f-string">f-string</h4>
<p>파이썬 3.6부터 지원하는 문법
문자열 앞에 f를 붙이면 { }안에 변수를 바로 사용 가능
기존의 format 메서드에 비해 코드가 짧고 가독성이 좋음</p>
<pre><code>print(f&quot;{name}의 학번은 {st_num}, 성적은 {score}입니다.&quot;)

# {변수명:형식지정자}
print(f&quot;{name}의 학번은 {st_num}, 성적은 {score:.2f}입니다.&quot;)
</code></pre><p>다양한 형식 지정자를 지정할 수 있다.</p>
<table>
<thead>
<tr>
<th align="left">형식 지정자</th>
<th align="left">문법</th>
<th align="left">예시</th>
</tr>
</thead>
<tbody><tr>
<td align="left">소수점 자리수</td>
<td align="left">:.nf</td>
<td align="left">f&quot;{3.141592:.2f}&quot;   # 3.14</td>
</tr>
<tr>
<td align="left">정수 자리수(0 패딩 포함)</td>
<td align="left">:0nd</td>
<td align="left">f&quot;{42:05d}&quot;   # 00042</td>
</tr>
<tr>
<td align="left">천단위 구분</td>
<td align="left">:,</td>
<td align="left">f&quot;{1234567:,}&quot;   # 1,234,567</td>
</tr>
<tr>
<td align="left">퍼센트</td>
<td align="left">:.n%</td>
<td align="left">f&quot;{0.1234:.2%}&quot;   # 12.34%</td>
</tr>
</tbody></table>
<h3 id="list-comprehension">List Comprehension</h3>
<p>for문을 통해 간단하게 리스트를 만들 수 있다.
문법은 다음과 같다.</p>
<blockquote>
<p>[리스트의 원소 for 변수 in 반복문의 범위]</p>
</blockquote>
<pre><code>[i for i in range(10)] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

[i * 2 for i in range(10)] # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

[i for i in range(1, 11) if i % 2 == 0] # [2, 4, 6, 8, 10]</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[생성형 AI 활용한 보안 프로그래밍 기술 - DAY1(2)]]></title>
            <link>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY12</link>
            <guid>https://velog.io/@aiden_lee/%EC%83%9D%EC%84%B1%ED%98%95-AI-%ED%99%9C%EC%9A%A9%ED%95%9C-%EB%B3%B4%EC%95%88-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EC%88%A0-DAY12</guid>
            <pubDate>Sat, 22 Nov 2025 07:13:16 GMT</pubDate>
            <description><![CDATA[<h2 id="파이썬">파이썬</h2>
<h3 id="함수">함수</h3>
<blockquote>
<p>def 함수명(입력 값):
    &emsp;&emsp;연산할 내용<br>    &emsp;&emsp;return 연산이 끝난 후 돌려줄 값 </p>
</blockquote>
<p>반환값이 여러개일 수 있다.
이 때에는 여러개의 변수로 반환값을 받는다.</p>
<pre><code>def func(x):
    y1 = x
    y2 = x * 2
    y3 = x * 3
    return y1, y2, y3

val1, val2, val3 = func(3)</code></pre><p>리턴값은 다양한 자료형이 될 수 있다.
함수는 아무것도 반환하지 않을 수 있다.(보통 출력값만 있는 경우)</p>
<p>파라미터 또한 여러개일 수 있다.</p>
<pre><code>def func(input1, input2, input3):
    result = input1 + input2 + input3
    return result

func(1, 2, 3)</code></pre><p><strong>❗함수에 전달되는 인자의 개수가 정해져 있지 않은 경우
-&gt; 파라미터로 <code>*args</code>를 지정</strong></p>
<p><code>*args</code>는 튜플(tuple) 형태로 전달됨.
따라서 인덱싱이나 반복 가능</p>
<p>ex) 함수에 여러 값을 넣어 sum을 구하는 경우</p>
<p><strong>❗함수에 전달되는 인자의 개수가 정해져 있지 않으며 키를 사용하는 경우
-&gt; 파라미터로 **```</strong>kwargs```<strong>를 지정</strong></p>
<p><code>**kwargs</code>는 딕셔너리(dict) 형태로 전달됨.</p>
<p><span style='color:#000000; background-color: #fff5b1'><em>args와 **kwargs로 전달될 인자 앞에 언패킹 연산자(</em>)와 (**)를 붙여야 함</span></p>
<h3 id="모듈-import-하기">모듈 import 하기</h3>
<pre><code>import pandas
# 없는 경우 설치한다.
# pip install pandas</code></pre><p>일부 모듈만 불러오는 경우</p>
<pre><code>from pandas import DataFrame</code></pre><p>as를 사용해 별명을 사용할 수 있다.</p>
<pre><code>import pandas as pd
pd.DataFrame()</code></pre><h3 id="if문">if문</h3>
<ul>
<li><p>if문 + list
리스트가 비어있으면 false, 원소가 있으면 true로 인식한다.</p>
</li>
<li><p>if문 + in list
if element in list:
else:
와 같이 사용한다.</p>
</li>
</ul>
<h3 id="for문">for문</h3>
<blockquote>
<p>for item in iterable:
    # do something</p>
</blockquote>
<pre><code>numbers = [10, 20, 30, 40, 50]

for num in numbers:
    print(num)</code></pre><ul>
<li>break문
조건 만족 시 반복문을 빠져나옴</li>
</ul>
<pre><code>for item in iterator:     
    # do something

    if condition:         
        break</code></pre><ul>
<li>continue문</li>
</ul>
<pre><code>for item in iterator:
     # [A] do something

    if condition:
        continue

    # [B] do something</code></pre>]]></description>
        </item>
    </channel>
</rss>