DataBase

일반적인 웹의 구조는 아래와 같다
WEB <=> WAS <=> DB

WAS의 동적화면이나 API를 개발할 때 사용되는 데이터의 저장을 담당하는것이 DB이다.

데이터베이스(영어: database, DB)는 여러 사람이 공유하여 사용할 목적으로 체계화해 통합, 관리하는 데이터의 집합이다.
-위키백과-

Table은 컬럼(column)과 로우(row)로 구성되며 컬럼의 데이터의 속성, row는 속성들의 집합이다.

위키백과

비유

DataBase: 엑셀파일

Table: 엑셀 시트

컬럼: 엑셀의 열

로우: 엑셀의 행


SQL

관계형 데이터베이스 관리 시스템(RDBMS)의 데이터를 관리하기 위해 설계한 특수 목적의 프로그래밍 언어이다. 관계형 데이터베이스 관리 시스템에서 자료의 검색과 관리, 데이터베이스 스키마 생성과 수정, 데이터베이스 객체 접근 조정 관리를 위해 고안하였다.
-위키백과-

즉 DB의 데이터를 관리하기 언어이다.

SQL은 크게 3가지로 나뉘게된다.

  • 데이터 정의 언어 (DDL : Data Definition Language) : DB의 구조 혹은 Table의 구조의 정의, 변경 (create, drop, alter)
  • 데이터 조작 언어 (DML : Data Manipulation Language): 데이터의 생성, 조회, 수정, 삭제 (insert, select, update, delete)
  • 데이터 제어 언어 (DCL : Data Control Language): 사용자 권한 부여 및 제거 등.(grant, revoke)

SELECT 간략한 구조

select [컬럼 명] from [테이블명] where [조건]

insert 구문의 간략한 구조

insert into [테이블] (컬럼명1, 컬럼명2) value ('값1', '값2')

'웹 해킹 코스 > 내용 정리' 카테고리의 다른 글

5주차 SQL Ijection  (2) 2023.11.26
4주차 (burp suitte)  (0) 2023.11.15
3주차 (쿠키, 세션)  (0) 2023.11.08
0주차 (리눅스 기초 명령어)  (2) 2023.10.26
1주차(WEB, WAS, IP, NAT)  (0) 2023.10.26

CSS자체가 어렵기도 하고 디자인적인 감각이 부족하기 때문에 다른 사이트의 로그인 페이지를 카피하고자 한다.

일단 버튼들을 비슷하게 구성하고 form태그를 삽입하자

~/flask01/templates/new_login.html을 생성한다.

네이버 페이지의 html 소스를 분석해보자

F12를 들어가서 개발자도구를 들어가 Elements탭을 클릭한 뒤 가장 왼쪽의 화살표를 클릭한 후 로그인 화면에 가저가보자

아래와 같이 화면이 어떻게 구역이 나뉘어져있는지, Elements 탭에는 어떤 Class와 Tag들이 사용되었는지 알 수 있다.

그리고 하단에는 Style이라고하여 어떤 CSS가 사용되었는지 볼 수 있다.

이것들을 참고하여 인스타그램의 로그인 화면을 만들어보자


결과

더 이상은 못하겟다...

이정도 만드는데도 한참 걸렸다 역시 CSS는 너무 어려운것 같다...
이번 작업중 icon 작업이 가장 힘들었는데 아이콘의 위치가 absolute가 걸려있는데 동적으로 어떻게 처리하는지 전혀 모르겠더라...

화면을 줄여버리자 날아가버리는 아이콘

이제 파이썬과 연동만 하면 과제 끝


 

수정된 app.py

# 이상 생략
@app.route('/login', methods=['GET'])
def login_get():
    msg = request.args.get('msg')
    print("msg: ",msg )
    return render_template('new_login.html', msg=msg)
#이하 생략

html 소스코드

<html>
    <body >
        <header class="heaer">
            <div class="heaer_inner">
                <img src="" alt="">
            </div>
        </header>
        <div class="content" style="margin-top: 20%;">
            <div class="login_wrap">
                <!-- <ul class="menu_wrap" role="tablist">
                    <li class="menu_item" role="presentation">
                        <span class="menu_text menu_qr"><span class="text">ID 로그인</span></span>
                    </li>
                    <li class="menu_item" role="presentation">
                        <span class="menu_text"><span class="text">일회용 번호</span></span>
                    </li>
                    <li class="menu_item" role="presentation">
                        <span class="menu_text"><span class="text">QR코드</span></span>
                    </li>
                </ul> -->
                <ul class="panel_wrap">
                    <li class="panel_item">
                        <form method="POST" action="/login">
                            <div class="panel_inner">
                                <div class="id_pw_wrap">

                                    <div class="input_row" id="id_line">
                                        <div class="icon_cell" id="id_cell">
                                            <span class="icon_id">
                                                <span class="blind">아이디</span>
                                            </span>
                                        </div>
                                        <input type="text" id="id" name="id" placeholder="아이디" title="아이디" class="input_text" maxlength="41" value="">
                                        <span role="button" class="btn_delete" id="id_clear" style="display: none;">
                                            <span class="icon_delete">
                                                <span class="blind">삭제</span>
                                            </span>
                                        </span>
                                    </div>


                                    <div class="input_row" id="pw_line">
                                        <div class="icon_cell" id="pw_cell">
                                            <span class="icon_pw">
                                                <span class="blind">비밀번호</span>
                                            </span>
                                        </div>
                                        <input type="password" id="pw" name="pw" placeholder="비밀번호" title="비밀번호" class="input_text" maxlength="16">
                                        <span role="button" class="btn_delete" id="pw_clear" style="display: none;">
                                            <span class="icon_delete">
                                                <span class="blind">삭제</span>
                                            </span>
                                        </span>
                                    </div>





                                </div>


                                <div class="btn_login_wrap">

                                    <button type="submit" class="btn_login" id="log.login">
                                        <span class="btn_text">로그인</span>
                                    </button>
                                        {% if msg != '' and msg != None %}
                                                {{msg}}
                                        {% endif %}
                                </div>

                            </div>
                        </form>

                    </li>
                </ul>
            </div>
        </div>
    </body>
</html>

<style>
.btn_login .btn_text {
    font-size: 20px;
    font-weight: 700;
    line-height: 24px;
    color: #fff;
}
 body {
    font-family: -apple-system,BlinkMacSystemFont,helvetica,"Apple SD Gothic Neo",sans-serif;
 }

    button, input, select, textarea {
    border-radius: 0;
    border: none;
    background: 0 0;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
    outline: 0;
    text-decoration: none;
    cursor: pointer;
    -webkit-text-size-adjust: none;
}
.input_row {
    /* position: relative; */
    display: block;
    /* height: 100%; */
    border: 1px solid #dadada;
    padding: 16px 18px 15px;
    border-radius: 6px;
    box-sizing: border-box;
    text-align: left;
    box-shadow: 0 2px 6px 0 rgba(68,68,68,.08);
}


.id_pw_wrap .input_row:last-child {
    border-radius: 0 0 6px 6px;
}

.btn_login {
    margin-top: 20px;
    display: block;
    width: 100%;
    padding: 13px 0 13px;
    border-radius: 6px;
    border: solid 1px rgba(0,0,0,.15);
    background-color: #03c75a;
    box-sizing: border-box;
}

.id_pw_wrap .input_row .icon_cell .icon_pw {
    background-position: -129px -203px;
    background-repeat: no-repeat;
    width: 16px;
    height: 16px;
}
    .blind {
    position: absolute;
    clip: rect(0 0 0 0);
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
}
/* 아이디 아이콘 */
.id_pw_wrap .input_row .icon_cell .icon_id {
    position: absolute;
    top: 24.4rem;
    left: 43.8rem;
    margin-top: -8px;
    background-position: -93px -203px;
    background-repeat: no-repeat;
    width: 16px;
    height: 16px;
}
/* pw 아이콘 */
.id_pw_wrap .input_row .icon_cell .icon_pw {
    position: absolute;
    top: 27.4rem;
    left: 43.8rem;
    margin-top: -8px;
    background-position: -129px -203px;
    background-repeat: no-repeat;
    width: 16px;
    height: 16px;
}
.bullet_help, .captcha_form .image::after, .captcha_form .reload::after, .captcha_form .voice::after, .captcha_wrap .voice_box .icon_voice, .chatbot .icon_chatbot, .icon_delete, .id_pw_wrap .input_row .icon_cell .icon_id, .id_pw_wrap .input_row .icon_cell .icon_pw, .id_pw_wrap .input_row.on .icon_cell .icon_id, .id_pw_wrap .input_row.on .icon_cell .icon_pw, .img_lock, .img_wowpoint, .ip_relogin_box .relogin_close::after, .ip_relogin_box .relogin_tip::before, .keep_check .keep_text::before, .keep_check input:checked+.keep_text::before, .lang::after, .menu_id .menu_text::before, .menu_id.on .menu_text::before, .menu_id.on::after, .menu_ones .menu_text::before, .menu_ones.on .menu_text::before, .menu_ones.on::after, .menu_ones.on::before, .menu_qr .menu_text::before, .menu_qr.on .menu_text::before, .menu_qr.on::before, .nudge_banner .nudge_close .icon_nudge_close, .ones_text .bullet_set, .pop_img_lock, .qrcode_help_stepbox .popup_close::after, .qrcode_help_stepbox .step_title::before, .reconfirm_sub .captcha_form .image::after, .reconfirm_sub .captcha_form .reload::after, .reconfirm_sub .captcha_form .voice::after, .reconfirm_sub .captcha_wrap .voice_box .icon_voice, .sns_wrap li:nth-child(1) .sns_text::before, .sns_wrap li:nth-child(2) .sns_text::before, .sns_wrap li:nth-child(3) .sns_text::before, .step_ask .ask_text::before, .sub_desc .bullet_greendot, .sub_desc .bullet_lens, .time_wrap .btn_renewal::before {
    background-image: url(https://ssl.pstatic.net/static/nid/login/m_sp_01_login_008d5216.png);
    background-size: 266px 225px;
    /* background-repeat: no-repeat; */
}

    .input_text {
    padding-left: 10px;
    position: relative;
    display: block;
    width: 100%;
    font-size: 16px;
    font-weight: 400;
    line-height: 19px;
    letter-spacing: -.5px;
    color: #222;
    box-sizing: border-box;
    z-index: 4;
}
.id_pw_wrap .input_row {
    display: table;
    table-layout: fixed;
    width: 100%;
    padding: 14px 17px 13px;
    box-sizing: border-box;
}
.id_pw_wrap .input_row:first-child {
    border-radius: 6px 6px 0 0;
    box-shadow: none;
}
.panel_inner {
    padding: 20px 28px;
}
.panel_item {
    border: 1px solid #c6c6c6;
    border-radius: 6px;
    background-color: #fff;
    box-shadow: 0 5px 8px 0 rgba(68,68,68,.04);
}

ol, ul {
    list-style: none;
}
.login_wrap {
    box-sizing: border-box;
    width: 460px;
    margin: 0 auto;
    }

/* 
    .menu_item {
    position: relative;
    display: table-cell;
    vertical-align: top;
}
    .menu_wrap {
    display: table;
    table-layout: fixed;
    width: 100%;
    border-collapse: collapse;
    }

    .header .logo {
    background-image: url(https://ssl.pstatic.net/static/nid/login/m_sp_00_common_978240a6.png);
    background-size: 244px 107px;
    background-repeat: no-repeat;
    display: inline-block;
    margin-top: 108px;
    vertical-align: top;
    background-position: 0 -51px;
    background-repeat: no-repeat;
    width: 155px;
    height: 30px;

}

    .header .header_inner {
    position: relative;
    width: 743px;
    margin: 0 auto;
    text-align: center;
    box-sizing: border-box;
}
  .header {
    padding-bottom: 48px;
    box-sizing: border-box;
} 

*/

</style>

비고

사실 로그인 페이지의 html과 CSS를 받아온다면 더욱 간단히 피싱 사이트를 만들 수 있을것 이다.

 

login 페이지를 카피한 html과 다운로드 받은 w_20220216.css

브라우저에서 확인해 본다면?

하지만 공부니까....

header, content, footer 모두 동일한 디자인을 확인 할 수 있다.

 

과제 끝

'웹 해킹 코스 > 과제' 카테고리의 다른 글

3-1(로그인 케이스)  (0) 2023.11.09
2-2 DB를 사용한 회원가입, 로그인  (0) 2023.11.02
2-1 php와 DB연결  (0) 2023.11.02
1-2 WAS POST방식 데이터 전달  (0) 2023.10.27
1-1 WAS 서버 만들기  (0) 2023.10.26

1-1에서 GET방식으로 데이터를 전달받고 동적으로 html을 구성하는 방법을 알아봤다.

이번 포스트에서는 POST 방식으로 데이터를 전달하는 테스트를 해보고자 한다.


~/webDev/flask01/templates/login.html 수정하기

msg 변수가 존재한다면 화면에 출력

<html>
        <form method="POST" >
                <p>ID: <input name="id" type="text" /> </p>
                <p>PW: <input name="pw" type="password" /><p/>
                <button type="submit"> login </button>
        </form>

        {% if msg != '' and msg != None %}
                {{msg}}
        {% endif %}
</html>

~/webDev/flask01/templates/login_success.html 생성

로그인 성공한 사용자의 id를 출력하기 위한 코드

<html>
        <h1>Hi {{id}}</h1>
</html>

~/webDev/flask01/app.py 수정

GET으로 /login에 접근하면 쿼리스트링에서 msg값을 msg변수에 할당하고 login.html과 msg를 함께 랜더링

POST로 /login에 접근하면 request body에서 id, pw값을 찾고 id, pw 변수에 할당
id,pw가 인가된 사용자라면 login_success.html과 id로 랜더링
비인가된 사용자라면 에러 메시지와 함께 login.html로 전달

from flask import Flask, render_template, redirect, request, url_for
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

@app.route('/login', methods=['GET'])
def login_get():
    msg = request.args.get('msg')
    print("msg: ",msg )
    return render_template('login.html', msg=msg)

@app.route('/login', methods=['POST'])
def login_post():
    id = request.form.get('id')
    pw = request.form.get('pw')

    if id == 'student' and pw == 'student1234':
        return render_template('login_success.html', id=id)
    else:
        msg = 'either ID or PW is wrong '
        return redirect(url_for('login_get', msg=msg))

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

결과

'웹 해킹 코스 > 과제' 카테고리의 다른 글

3-1(로그인 케이스)  (0) 2023.11.09
2-2 DB를 사용한 회원가입, 로그인  (0) 2023.11.02
2-1 php와 DB연결  (0) 2023.11.02
1-3 CSS를 사용하여 로그인 페이지 꾸미기  (0) 2023.10.29
1-1 WAS 서버 만들기  (0) 2023.10.26

1주차 과제: 로그인 페이지 만들기

1. python이 설치되어 있는관계로 간단하게 Flask를 사용할 예정
2. Flask에서 html탬플릿 엔진을 사용하기위한 방법 찾아보기


Flask 설치 준비

# 만일의 사태를 대비해 가상환경으로 진행
mkdir ~/flaskWAS
cd flaskWAS

# pip 설치
sudo apt install python3-pip

# 가상환경 패키지 설치
sudo apt install python3.10-venv

# 가상환경 생성
python3 -m venv flask01

# activate 심볼릭 링크생성
cd ~
ln ~/flaskWAS/flask01/bin/activate ~/activate

#가상환경 실행
source activate

좌측에 기입한 가상환경 이름이 보인다(flask01)

이제 패키지 충돌 걱정 없이 Flask 및 Template engine을 설치하면된다.


Flask 설치

# flask 설치
pip install flask

# 플라스크 설치 확인 
pip list

flask 3.0.0 설치 확인


# flask 소스 작성
cd flaskWAS
vi app.py

하기의 내용 기입 후종료

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Flask에서 host를 기입 하지 않는다면 외부에서 접근이 불가능하고 localhost에서만 접근이 가능하다
ps.이것 때문에 3시간을 날렸다....
app.run(host='0.0.0.0', port=5000)

# flask 실행
python app.py

실행이 되었다면 Host에서 접근해 보자

VM에서 실행한 Flask를 Host에서 접근이 가능한 것을 볼 수 있다.

ctl + c를 사용하여 종료한다.


탬플릿 적용

확인해 본 결과 Flask에 html을 호출 할 수 있는 모듈이 존재 한다 (추가적으로 설치할 것이 없다)

# app.py와 동일한 위치에 templates 디렉토리를 생성한다. 
# 플라스크에서 사용하는 html의 기본 위치는 template가 된다.
mkdir templates
cd templates

# html을 작성하여 GET 방식의 데이터를 받아보자
# {{id}}는 탬플릿 엔진에서 받는 변수를 바인딩 한다.
vi login.html

---- 이하 파일 내용
<html>
        <form method="GET">
                <input name="id" type="text" />
        </form>

        <h1>id is {{id}}</h1>
</html>
-------------------

 

app.py에 login.html을 호출 할 수있는 라우터(Spring Controller) 설정을 해주어야한다.

cd ~/flaskWAS
vi app.py
--------이하 파일내용
from flask import Flask, render_template, request
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

@app.route('/login')
def login_1():
    id = request.args.get('id')
    return render_template('login.html', id=id) 


if __name__ == '__main__': 
    app.run(host='0.0.0.0', port=5000)
--------------------

간단 설명

from flask import Flask, render_template, request

  • flask 모듈에서 renter_template, request를 import 받는다.

@app.route('/login')

  • ip:port/login 으로 들어오는 url에 대한 처리를 하는 함수를 지정한다.

id = request.args.get('id')

  • requst(요청)으로 받은 arguments 중 id값을 찾아 id 변수에 assign한다.

return render_template('login.html', id=id)

  • renter_template 처리 결과를 반환하며 사용할 html은 login.html
  • 랜더링 시 사용할 id라는 변수에 python에서 정의한 id를 할당한다.

저장 후 다시 python app.py를 실행하여 ip:5000/login으로 접속해보자.

 

url에 쿼리스트링이 없으므로 request.args.get('id')의 값은 None 이다.

input 태그에 아이디를 기입하고 엔터를 누르면

 

id가 동적으로 표기되는 것을 볼 수 있다.

 

다음 포스트는 GET 방식이아닌 POST 방식으로 데이터를 전달하고
특정 ID와 PW일 경우 로그인성공, 그 외는 로그인 실패 메시지를 표기할 수 있도록 수정하겠다.

 

최종 상태

~/devWeb/flaskWAS 파일 상태
~/devWeb/flaskWAS/tempaltes/login.html

 

~/devWeb/flaskWAS/app.py

+ Recent posts