<?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>Fri, 24 Apr 2026 05:29:48 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[[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>
        <item>
            <title><![CDATA[생성형 AI 활용한 보안 프로그래밍 기술 - DAY1(1)]]></title>
            <link>https://velog.io/@aiden_lee/DAY1</link>
            <guid>https://velog.io/@aiden_lee/DAY1</guid>
            <pubDate>Sat, 22 Nov 2025 04:17:15 GMT</pubDate>
            <description><![CDATA[<h2 id="파이썬">파이썬</h2>
<p>❗유의사항</p>
<h3 id="리스트">리스트</h3>
<p>리스트의 remove함수
index가 아닌 값을 지정하여 제거.</p>
<pre><code>a = [1, &#39;가나디&#39;, 3.14, &#39;사과&#39;]
a.remove(1)
a</code></pre><blockquote>
<p>a = [&#39;가나디&#39;, 3.14, &#39;사과&#39;]</p>
</blockquote>
<pre><code>a.remove(&#39;사과&#39;)
a</code></pre><blockquote>
<p>a = [&#39;가나디&#39;, 3.14]</p>
</blockquote>
<ul>
<li>지정한 값이 중복으로 존재하는 경우
앞에서부터 순서대로 하나만 제거됨.</li>
</ul>
<pre><code>a.append(1)
a.append(1)
a</code></pre><blockquote>
<p>a = [&#39;가나디&#39;, 3.14, 1, 1]</p>
</blockquote>
<pre><code>a.remove(1)
a</code></pre><blockquote>
<p>a = [&#39;가나디&#39;, 3.14, 1]</p>
</blockquote>
<h3 id="튜플">튜플</h3>
<p>튜플은 수정이 불가한 자료형. 값을 바꿀 수 없다.
-&gt; 리스트로 변환 후 수정하고 다시 튜플로 변환하는 방식 가능</p>
<pre><code>A = (&#39;a&#39;, 9, 5.15) # 튜플
ch = list(A) # 리스트 변환
ch.append(3)
newA = tuple(ch) # 튜플 전환</code></pre><h3 id="세트">세트</h3>
<p>세트는 순서 상관X, 중복 제거
순서를 가지지 않으므로 인덱스 접근 불가.
인덱싱, 슬라이싱 등등 모두 불가</p>
<blockquote>
<p>[ ] : 대괄호. 리스트
{ } : 중괄호. 세트
( ) : 소괄호. 튜플</p>
</blockquote>
<h3 id="딕셔너리">딕셔너리</h3>
<p>딕셔너리 역시 인덱스 접근 불가. 순서 지정돼있지 않으므로
대신 key값을 이용해 value 접근 가능</p>
<p>원소 삭제 시 del함수 이용</p>
<pre><code>dict = {&#39;key1&#39;:666, &#39;key2&#39;:888}
del dict[&#39;key1&#39;]
dict</code></pre><blockquote>
<p>{&#39;key2&#39;:888}</p>
</blockquote>
<p>zip함수를 사용하면 두 리스트를 하나의 딕셔너리로 생성 가능.</p>
<pre><code>key = []
value = []
zip(key, value)</code></pre><h3 id="문자열">문자열</h3>
<p>문자열 처리</p>
<p>인덱싱 가능.
공백도 인덱스를 가짐.</p>
<p><span style='color:#000000; background-color: #fff5b1'>❗파이썬에서 문자열은 <strong>변경 불가능한 자료형</strong>
-&gt; 인덱스 지정하여 특정값 변경하는 것 불가.
replce 함수를 사용하더라도, 새로운 스트링을 반환하는 것이지 해당 문자열이 변경되는 것은 아님.</span></p>
<pre><code>str1 = &#39;abcde&#39;
str1[4] = &#39;s&#39; # error
str1.replace(&#39;a&#39;, &#39;b&#39;) # &#39;bbcde&#39;반환. 하지만 str1은 여전히 &#39;abcde&#39;이다.</code></pre><blockquote>
<p>&#39;bbcde&#39;</p>
</blockquote>
<p>한 번 지정된 문자열 str1은 변경되지 않는다.
따라서 새로 반환한 문자열을 저장하고 싶은 경우 <code>str2 = str1.replace(&#39;a&#39;, &#39;b&#39;)</code>와 같이 따로 저장해야 함.</p>
<p>replace는 replaceAll로 작동한다.</p>
<pre><code>str = &#39;abbbabaa&#39;
str.replace(&#39;a&#39;, &#39;b&#39;) # str의 모든 a가 b로 대체됨</code></pre><blockquote>
<p>&#39;bbbbbbbb&#39;</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[졸업 프로젝트: 트러블 슈팅(1)]]></title>
            <link>https://velog.io/@aiden_lee/%EC%A1%B8%EC%97%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%851</link>
            <guid>https://velog.io/@aiden_lee/%EC%A1%B8%EC%97%85-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%8A%B8%EB%9F%AC%EB%B8%94-%EC%8A%88%ED%8C%851</guid>
            <pubDate>Thu, 28 Nov 2024 11:33:31 GMT</pubDate>
            <description><![CDATA[<p>테이블 DROP 후 다시 생성이 안 돼서 이틀을 꼬박 잡아먹고 지쳐있었다. 보통 application.yml 파일 문법의 문제라고 나와 있는데, 나는 도대체 어디가 틀린건지 찾을 수가 없었다...
그러던 중, 질문글의 해답을 보고 혹시...?하는 마음에 고쳐보자 바로 테이블이 생성되었다. 해결되어 다행!</p>
<pre><code>  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect
        ddl-auto: create
</code></pre><p>이 부분을 다음과 같이 고쳐야 한다.</p>
<pre><code>  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect</code></pre><p>고치기 전</p>
<pre><code>spring:
  application:
    name: hong-yeon
  h2:
    console:
      enabled: true
      path: /h2-console
  datasource:
    url: jdbc:h2:file:./local
    driver-class-name: org.h2.Driver
    username: sa
    password: &quot;&quot;
  jpa:
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect
        ddl-auto: create
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
server:
  port: 8020
</code></pre><p>고친 후</p>
<pre><code>spring:
  application:
    name: hong-yeon
  h2:
    console:
      enabled: true
      path: /h2-console
  datasource:
    url: jdbc:h2:file:./local
    driver-class-name: org.h2.Driver
    username: sa
    password: &quot;&quot;
  jpa:
    hibernate:
      ddl-auto: create
    properties:
      hibernate:
        dialect: org.hibernate.dialect.H2Dialect
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
server:
  port: 8020</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Baekjoon:10250]]></title>
            <link>https://velog.io/@aiden_lee/Baekjoon10250</link>
            <guid>https://velog.io/@aiden_lee/Baekjoon10250</guid>
            <pubDate>Wed, 21 Feb 2024 06:11:53 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/10250">https://www.acmicpc.net/problem/10250</a></p>
<p>이 문제의 경우 수학 계산식에서 오류가 있었다.</p>
<p>우선 첫 번째 제출</p>
<pre><code class="language-java">import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;

public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int repeat = scanner.nextInt();
        int H, W, N;
        List&lt;Integer&gt; floor = new ArrayList&lt;&gt;();
        List&lt;Integer&gt; roomNumber = new ArrayList&lt;&gt;();

        for(int i = 0; i &lt; repeat; i++) {
            H = scanner.nextInt();
            W = scanner.nextInt();
            N = scanner.nextInt();

            roomNumber.add(N / H + 1);

            if(N % H == 0) {
                floor.add(H);
            } else{
                floor.add(N % H);
            }
        }

        for(int i = 0; i &lt; repeat; i++) {
            System.out.printf(&quot;%d%02d\n&quot;, floor.get(i), roomNumber.get(i));
        }
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/c1e158e5-a148-452e-9683-3cef17e70b43/image.png" alt=""></p>
<p>예제 입출력은 잘 나와서 뭐가 잘못된거지? 했었던 문제.</p>
<p>하지만 질문 게시판을 눌러보니 바로 잘못된 출력을 찾았다.</p>
<blockquote>
<p><span style="color: green">1
10 10 10</span>
1002</p>
</blockquote>
<p>이 입력은 1001이 나와야 한다. 1이 더 크게 나오자 바로 문제를 눈치챘다. 층에 대한 조건문은 작성했으면서 호수에 대한 조건문은 작성하지 않았다.
어떤 경우에도 상관없이 <code>roomNumber.add(N / H + 1);</code>가 호수가 되도록 한 것이 문제였다. 이 부분도 나머지가 0이고 딱 꼭대기 층인 경우, +1을 해주면 안된다.</p>
<p>따라서 이렇게 수정하였다.</p>
<pre><code class="language-java">import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;

public class Main{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        int repeat = scanner.nextInt();
        int H, W, N;
        List&lt;Integer&gt; floor = new ArrayList&lt;&gt;();
        List&lt;Integer&gt; roomNumber = new ArrayList&lt;&gt;();

        for(int i = 0; i &lt; repeat; i++) {
            H = scanner.nextInt();
            W = scanner.nextInt();
            N = scanner.nextInt();

            //조건문으로 수정한 부분
            if(N % H == 0) {
                roomNumber.add(N / H);
            } else{
                roomNumber.add(N / H + 1);
            }

            if(N % H == 0) {
                floor.add(H);
            } else{
                floor.add(N % H);
            }
        }

        for(int i = 0; i &lt; repeat; i++) {
            System.out.printf(&quot;%d%02d\n&quot;, floor.get(i), roomNumber.get(i));
        }
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/aiden_lee/post/d5a9d955-57f2-4a18-9caa-9e9cd7c48d23/image.png" alt=""></p>
<p>한 번에 통과할 수는 없는걸까
꼭 한 번씩은 틀리게 된다.ㅎㅎ</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Paging]]></title>
            <link>https://velog.io/@aiden_lee/Paging</link>
            <guid>https://velog.io/@aiden_lee/Paging</guid>
            <pubDate>Sun, 21 Jan 2024 08:21:44 GMT</pubDate>
            <description><![CDATA[<h2 id="paging">Paging</h2>
<p>모든 데이터가 한 페이지에 표시되도록 설계해서는 안된다. 페이징을 통해 한 페이지당 보이는 데이터의 양을 제한할 것이다.
이 때, 라이브러리를 추가로 설치하지 않고 이미 설치해두었던 JPA 관련 라이브러리를 사용한다.
Spring Data 프레임워크에서 제공하는 페이징 관련 클래스로는 다음과 같은 클래스가 있다.</p>
<ul>
<li>org.springframework.data.domain.Page: 페이징을 위한 클래스.</li>
<li>org.springframework.data.domain.PageRequest: 페이징 요청을 하는 클래스. 한 페이지에 보여 줄 게시물 개수 설정 등 옵션을 걸어 요청할 수 있다.</li>
<li>org.springframework.data.domain.Pageable: 페이징을 처리하는 인터페이스.</li>
</ul>
<h3 id="page">Page</h3>
<p><strong>Page 클래스</strong>는 특정 페이지에 포함된 데이터와 페이징 관련 정보를 담고 있는 클래스이다. 대표적으로 다음과 같은 메서드가 존재한다.</p>
<ul>
<li><code>getContent()</code> : 해당 페이지에 포함된 데이터를 리턴.  일반적으로 데이터는 List 형태로 반환 된다.</li>
<li><code>getTotalElements()</code> : 전체 데이터의 개수 리턴</li>
<li><code>getTotalPages()</code> : 전체 페이지 수 리턴</li>
<li><code>getNumber()</code> : 현재 페이지의 인덱스 번호를 반환. 페이지 인덱스는 0부터 시작</li>
<li><code>getSize()</code> : 한 페이지에 포함된 항목의 개수를 반환</li>
<li><code>getSort()</code> : 페이지 내 항목의 정렬 순서를 반환. Sort 객체로 반환되며, 정렬 기준을 확인할 수 있다.</li>
</ul>
<h3 id="pageable">Pageable</h3>
<p><strong>Pageable 인터페이스</strong>는 페이징 처리를 위한 정보를 담고 있는 인터페이스이다. <code>Pageable</code> 인터페이스를 구현한 클래스로는 <code>PageRequest</code>가 있다. <code>Pageable</code> 인터페이스에는 다음과 같은 메서드가 존재한다.</p>
<ul>
<li><code>getPageNumber()</code>: 조회할 페이지 번호를 반환. 0부터 시작</li>
<li><code>getPageSize()</code>: 한 페이지에 포함될 항목의 개수를 반환</li>
<li><code>getOffset()</code>: 조회할 페이지의 시작 위치를 반환</li>
<li><code>getSort()</code>: 페이지 내 항목의 정렬 순서를 반환</li>
</ul>
<p><code>Pageable</code> 인터페이스는 데이터를 조회하는 메서드에 <code>Pageable</code> 객체를 인자로 전달하여 페이징 처리를 할 수 있도록 한다. 다음 예시와 같이 사용할 수 있다.</p>
<pre><code class="language-java">Pageable pageable = PageRequest.of(0, 10); // 첫 번째 페이지, 페이지당 10개의 항목
Page&lt;User&gt; userPage = userRepository.findAll(pageable);
List&lt;User&gt; userList = userPage.getContent(); // 페이지에 포함된 User 데이터 리스트</code></pre>
<p><code>PageRequest</code> 객체를 사용하여 <code>Pageable</code> 인터페이스를 구현한 객체를 생성한 후, <code>userRepository.findAll()</code> 메서드에 전달하여 첫 번째 페이지의 10개 User 데이터를 조회한 예시이다.</p>
<p><code>Page</code>와 <code>Pageable</code>을 함께 사용하면 데이터를 효과적으로 페이징하여 처리할 수 있다.</p>
<h3 id="pagerequest">PageRequest</h3>
<p>페이징 처리를 위한 정보를 담고 있으며, 데이터를 조회할 때 사용되는 메서드들에게 정보를 전달하여 특정 페이지의 데이터를 가져올 수 있다.</p>
<p><code>PageRequest</code> 클래스의 주요 속성과 생성자는 다음과 같다.</p>
<ul>
<li><code>page</code>: 가져올 페이지의 번호. 0부터 시작하며, 기본값은 0이다.</li>
<li><code>size</code>: 한 페이지에 포함될 항목의 개수. 기본값은 20이다.</li>
<li><code>sort</code>: 페이지 내 항목의 정렬 순서를 지정. <code>Sort</code> 객체를 사용하여 정렬 기준을 설정할 수 있다.</li>
</ul>
<p><code>PageRequest</code> 객체를 생성하기 위해 다음과 같은 생성자를 사용할 수 있다.</p>
<ul>
<li><code>PageRequest.of(int page, int size)</code>: 기본 생성자로, <code>page</code>와 <code>size</code> 값을 인자로 받아 <code>PageRequest</code> 객체를 생성한다.</li>
<li><code>PageRequest.of(int page, int size, Sort sort)</code>: 정렬 기준을 추가로 지정하여 <code>PageRequest</code> 객체를 생성한다.</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>