웹 해킹 문제를 푸는데 Flask 사용법을 몰라 문제를 풀 때 한참 헤멨다.

Flask 사용법을 점차 익혀야겠다.

 

 

 

문제 페이지 소스코드

Flask 에서 처리하기 전에 먼저 html 소스에서 <form><input> 에 보면 name 이라는 속성이 있다.

이 name의 속성 값이 중요하다.

클라이언트에서 서버로 데이터를 전송할 때 이름과 값의 쌍이 전송이 되는데 이 형태는 key 와 value로 표현이 될 수 있다.

그래서 <input type="text" name="xss"> 에서 xss 이라고 하는 것이 key가 되고  이 텍스트 박스에서 입력된 내용은 value가 된다.

 

 

app.py

@라고 되어있는 부분은 파이썬에서 데코레이터(decorator)라고 부르며, 이를 사용하여 app의 객체의 route 함수에 request 인자를 넘기면서 HTTP 요청을 처리한다.

request는 보통 get, post 방식으로 넘어온 데이터를 처리할 때 필요하다.

사실 "request"는 서버 측에서 요청한다는 의미. 즉, 사용자가 서버로 보내오는 요청이나 데이터를 얻어내는 역할을 하는 것이 이 request 객체의 역할이다.

GET 방식으로 요청 파라미터를 가져오려면 request 객체의 args 함수를 호출하면 된다.

POST 방식으로 요청 파라미터를 가져오려면 request 객체의 form 함수를 호출하면 된다.

+ get 함수의 첫 번째 인자는 요청 파라미터명, 두 번째 인자는 해당 요청 파라미터가 없을 시의 초기값이다.

 

밑의 함수는 @app.route 데코레이터 URL과 자신을 연결한다.

 

저기에서 '/'로 요청(request)을 하면 (즉 http://127.0.0.1/(생략가능) 여기로 접속하면) index() 함수가 실행된다는 것이다.

 

** HTTP 요청 방식

클라이언트에서 웹 서버로 요청할 때 어떤 방식으로 데이터를 전달할 것인지를 정한다. 

GET 서버로부터 정보를 조회 또는 요청(데이터를 Body에 담지 않고 URL에 쿼리스트링을 통해 전송)
가장 일반적인 요청 방식
* 쿼리스트링: URL의 끝에 ?와 함께 이름과 값으로 쌍을 이루는 요청 파라미터 (파라미터가 여러 개이면 &로 연결)
HEAD GET 요청으로 반환될 데이터 중 헤더 부분에 해당하는 데이터만 요청
POST 클라이언트에서 서버로 처리할 수 있는 데이터를 보냄(데이터를 HTTP 메세지의 Body에 담아서 전송)
보통 HTML 폼을 통해 데이터를 전송
PUT 클라이언트가 서버에게 지정한 URL에 지정한 데이터를 저장할 것을 요청. POST와 유사
DELETE 클라이언트가 서버에게 지정한 URL의 정보를 제거할 것을 요청
OPTIONS 해당 URL에서 지원하는 request method를 알려줌

 

 

'WEB > WEB Hacking' 카테고리의 다른 글

Dreamhack | 워게임 | <csrf-1> 문제  (0) 2021.01.26
Client-side Attack  (0) 2021.01.25
Dreamhack | 워게임 | <xss-1> 문제  (0) 2021.01.23
웹 해킹 기초  (0) 2021.01.23
Dreamhack | 워게임 | <simple_sqli>문제  (0) 2020.11.19

 

처음 화면

xss, memo, flag 각각의 페이지가 있다.

 


분석

xss 클릭시 나오는 화면

자세히 보면 xss 값에 <script>alert(1)</script>가 들어가 있다.

그리고 이에 대해 그대로 그 결과를 보여주었다는 것은

웹 페이지 내에서 XSS 공격이 가능하다는 의미이다.

 

 

 

memo 클릭시 나오는 화면

memo를 클릭했을 때는 memo안에 hello 값이 들어가있고,

이를 화면에 출력하고 있다.

 

 

 

flag 클릭시 나오는 화면
flag.html의 소스코드 확인

 

이 부분이 중요해 보였다.

'xss라는 이름으로 POST 방식으로 넘겨지는 요 부분'이 우리가 채울 부분이다.

 

 

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/xss') 
def xss():
    xss = request.args.get('xss', '') 
    return xss 

@app.route('/flag', methods=['GET', 'POST'])
def flag():
    if request.method == 'GET':
        return render_template('flag.html')
    elif request.method == 'POST': 
        xss = request.form.get('xss') 
        if not read_url(xss, {'name': 'flag', 'value': FLAG}):
            return '<script>alert("wrong??");history.go(-1);</script>'

        return '<script>alert("good");history.go(-1);</script>'

memo_text = ''
@app.route('/memo')
def memo():
    global memo_text
    text = request.args.get('memo', None)
    if text:
        memo_text += text.replace('<', '&lt;') + '\n'
    return render_template('memo.html', memo=memo_text)

↑app.py 코드 일부

 

[GET] /xss 에서는 xss 파라미터가 그대로 출력되고,

[GET] /memo에서는 'memo' 파라미터를 저장(text)하고 저장된 값(memo_text)들을 보여준다.

[POST] /flag 에선 read_url 로 'xss' 파라미터와 'flag' 쌍을 넘겨준다.

 

 

아무리 고민해도,, 어디부터 봐야할지 감이 안 잡혀 힌트를 봤는데, 먼저 /memo가 왜 있는지 생각해보라고 했다.

나중에 알아냈지만 /memo의 역할은 get 방식으로 'memo' 파라미터 값으로 쿠키값(document.cookie)을 전달받으면

이 페이지에 나타내도록 하는 것이다.

 

/memo에서 궁금한게 있었다. 왜 replace 함수를 사용해서 < 부등호를 &lt;로 변환을 할까?

자바스크립트를 이용한 공격을 막기 위해서?

 

 

def read_url(url, cookie={'name': 'name', 'value': 'value'}):
    cookie.update({'domain':'127.0.0.1'})
    try:
        options = webdriver.ChromeOptions()
        for _ in ['headless', 'window-size=1920x1080', 'disable-gpu', 'no-sandbox', 'disable-dev-shm-usage']:
            options.add_argument(_)
        driver = webdriver.Chrome('/chromedriver', options=options)
        driver.implicitly_wait(3)
        driver.set_page_load_timeout(3)
        driver.get('http://127.0.0.1:8000/') #URL에 접근
        driver.add_cookie(cookie)
        driver.get(f'http://127.0.0.1:8000/xss?xss={urllib.parse.quote(url)}')
        #urllib.parse.quote(string, safe='/', encoding='utf-8', errors='strict'): 인자로 주어진 문자열에서 특수문자를 문자열로 변환해서 반환
    except:
        driver.quit()
        return False
    driver.quit()
    return True

그 후, 핵심 코드인 read_url을 이해하려 하였다.

 

/flag 페이지에서 'xss'의 데이터를 POST 방식으로 보내면 read_url 함수가 동작하는데,

read_url에선 flag 쌍을 'cookie'로 설정하고,

FLAG 변수의 내용이 담긴 flag 쿠키가 생성(add_cookie(cookie))된다

 

그 후, /xss?xss={입력한 부분} 으로 get request를 보낸다.

따라서 'xss' 값을 아래와 같이 적으면 document.cookie를 memo에 입력할 수 있게 된다.

 

 

처음에 이해가 안 갔던 것은 driver.get(f'http://127.0.0.1:8000/xss?xss={입력한 부분}') 이 코드가 왜 필요한가,, 였는데

이게 진짜 핵심이었던 것..

접속하는 호스트에 서버를 연결시켜 XSS 공격을 유발하도록 하는 부분이었다.

(이 문제에서 공격자는 로컬(나)이기 때문에 주소를 http://127.0.0.1/로 설정하는 것임)

 

 

 

빈칸 입력

빈칸에 <script>location.href="/memo?memo="+document.cookie;</script>를 입력.

location.href를 통해 지정한 위치(해커 사이트, memo)로 리다이렉션되고, document.cookie 정보를 함께 입력시켜

사용자의 쿠키가 지정한 위치(해커 사이트, memo)에 출력된다.

 

 

 

memo 페이지

즉, /xss페이지에 'xss'값이 전달되고 실행되어 '잠깐 동안 존재했던 flag 쿠키'가 /memo 페이지에 기록된다.

 

더보기

Flask에서 GET,POST 사용하는 방법 조금씩 익히기

# render_template : html 파일 불러옴

# GET과 POST는 둘 다 서버로 요청하는 방식
# GET 방식 : 모든 파라미터를 url로 보내는 것(눈에 보임) => Flask에서 제공하는 request객체의 args 함수 호출

# get 함수의 첫 번째 인자는 요청 파라미터명, 두 번째 인자는 초기값, 그 다음은 타입

# POST 방식 :전달하려는 정보가 HTTP Body에 포함되어 전달되는 것(눈에 안보임) => request 객체의 form 함수 사용

 

더보기

꼭 알아둘 웹 사이트에서 정보 탈취나 위치 이동&변조가 가능한 코드들!

<script>

alert("hi"); <!--메시지 출력-->

document.cookie; <!--쿠키값-->

location.href=""; <!--""내의 링크로 위치 이동-->

document.location=""; <!--""링크로 이동-->

</script>

 


주절주절 썼지만

계속 풀면서 들었던 생각은

'탄탄한 기본기 갖추기'라는 것이다. 

까먹거나 모르는 부분을 쬐금씩 찾으면서 하니까 너무 오래걸렸다.

다시 공부하러,, 고고╭(๑•̀ㅂ•́)و

'WEB > WEB Hacking' 카테고리의 다른 글

Client-side Attack  (0) 2021.01.25
Flask, HTTP 요청 방식  (0) 2021.01.24
웹 해킹 기초  (0) 2021.01.23
Dreamhack | 워게임 | <simple_sqli>문제  (0) 2020.11.19
Dreamhack | 워게임 | <cookie>문제  (0) 2020.11.19

웹 

:: 월드 와이드 웹(World Wide Web) 또는 웹(Web) 

:: 거미줄(Web)에서 따온 이름으로, 서로 연결되어 정보를 공유한다는 의미에서 사용

 

인터넷 상의 서비스 중 HTTP를 이용하여 정보를 공유하는 통신 서비스가 웹(Web)이며

서비스를 제공하는 대상을 웹 서버(Web Server), 서비스를 받는 사용자를 웹 클라이언트(Web Client)라고 부른다.

 

초기 웹은 단지 페이지 상에서 문자를 출력해주는 역할이 컸지만 ,

오프라인 상의 물리적이었던 정보들이 웹 안으로 들어오게 되면서 

보안의 중요성이 커지게 된다.

 

 

웹 해킹 개요

크게 Client-side Attack, Server-side Attack으로 나뉜다.

 

ⓐ Client-side Attack

:: 서비스 사용자에 대한 공격

웹을 이용하는 사용자는 웹 브라우저를 통해 서비스를 제공받는데, 웹 서버가 제공해주는 데이터가 공격자에 의해 변조되었을 경우 웹 브라우저에서 렌더되는 과정에서 취약점이 발생하는 경우가 대표적

 

ⓑ Server-side Attack

:: 서버에 대한 공격

운영되는 서비스의 구조와 특징에 따라 다양한 공격 형태가 존재하며, 공격자가 공격에 성공하게 되면 서버의 어플리케이션 코드 또는 다른 사용자의 정보 유출, 서버 탈취 등으로 이어질 수 있음

'WEB > WEB Hacking' 카테고리의 다른 글

Client-side Attack  (0) 2021.01.25
Flask, HTTP 요청 방식  (0) 2021.01.24
Dreamhack | 워게임 | <xss-1> 문제  (0) 2021.01.23
Dreamhack | 워게임 | <simple_sqli>문제  (0) 2020.11.19
Dreamhack | 워게임 | <cookie>문제  (0) 2020.11.19

PE File Format

:: Windows 운영체제에서 동작하는 실행 파일의 구성 방식

:: 실행 파일이 어떻게 구성되어야 하는지, 그 원칙을 정의해 놓은 것

:: Microsoft가 운영체제를 설계하는 과정에서 실행파일의 효율적이고 합리적인 구성을 고민하고 선택한 방식

:: 다양한 운영체제에서의 이식성을 보여준다는 뜻에서 이식이 가능한 실행형식(Portable Executable)이라는 이름이 붙음

 

PE 파일의 종류

ⓐ 실행 파일 계열 : EXE, SCR(Screen Saver)

ⓑ 라이브러리 계열 : DLL, OCX(Active X)

ⓒ 드라이브 계열 : SYS

ⓓ 오브젝트 파일 계열 : OBJ

 

PE 파일을 만들 떄, 일반적으로 Visual Studio와 같은 개발 도구를 사용한다.

(개발 도구 → 코드 작성 → 컴파일 → 실행 파일(exe)완성)

 

 

실행 파일을 만드는 과정은 어떻게 될까?

1. 코드와 데이터를 분리 (실행 코드 : .text 섹션에 기록 // 데이터 : .data 섹션에 기록)

2. 코드 → 기계어로 변환

3. 문자열 데이터 아스키 값으로 변환

4. 명령코드와 아스키 값을 담기 위한 생성 (PE File Format)

5. PE 헤더 작성 (PE헤더 : 파일 실행에 필요한 정보가 기록되어 있는 영역)

   --- 사용자가 작성한 값이 아니라, 코드를 컴파일하는 과정에서 컴파일러가 알아서 작성함

   --- 컴파일러가 PE 파일에 Header를 기록하는 이유 ? PE 파일을 만드는 것은 컴파일러지만, 실행 주체는 운영체제

                                                                       따라서 운영체제 입장에서 PE 파일을 실행하기 위해 필요한 정보를 담아줘야 함

6. 명령코드 채움 (.text 섹션 : 파일이 동작하는 데 필요한 코드가 기록되어 있는 영역)

7. 데이터 채움 (.data 섹션 : 파일이 실행될 때 필요한 부가적인 정보가 기록되어 있는 영역)

8. 실행 파일 완성!

 

 

 

'Study > Reversing' 카테고리의 다른 글

main 함수 찾기  (0) 2021.03.23
OllyDBG, 어셈블리어  (0) 2021.02.04
IAT & EAT  (0) 2021.01.25
PE 헤더  (0) 2021.01.24
리버싱의 이해  (0) 2021.01.22

리버싱

:: 소프트웨어 공학의 한 분야로, 이미 만들어진 시스템을 역으로 추적하여

처음의 문서나 설계기법 등의 자료를 얻어내는 일

 

즉, 사람이 인식하기 어려운 기계어를 재번역하고, 재번역된 코드를 읽어서 기능과 역할을 알아낸다고 보면 된다.

 

 

소스코드

 

Visual Studio 와 같은 개발 툴을 이용해서 코드를 작성하고 컴파일을 하면 실행 파일이 만들어진다.

TEST.exe 파일 확인

 

실행파일이 만들어졌다는 것은 우리가 작성한 코드가 기계어로 변환되었음을 의미한다.

 

기계어로 번역된 main()코드의 일부

 

그리고 이 기계어를 CPU가 읽어서 문자열을 출력시킨다.

TEST.exe 파일 실행

------------------------------------------------------------------------------------------------------------------------------

 

이제 실행 파일을 리버싱해보자

앞서 언급했듯이 실행 파일에는 기계어로 번역된 main() 함수 코드가 있다.

하지만 우리는 기계어를 읽을 수 없다.

 

따라서 리버싱 작업은 보통 WinDBG나 IDA, OllyDBG와 같은 디버깅(디컴파일러) 툴을 사용해서 이루어진다.

이러한 툴들은 사람이 인식하기 어려운 기계어를 재번역하는 데 일차적인 목적이 있다.

 

OllyDBG.exe와 같은 툴로 TEST.exe 파일을 확인하면 

기계어에서 어셈블리어로 재번역된 main()함수 코드를 확인할 수 있다.

 

TEST.exe 메인코드

 

리버싱은 한 마디로, "디버거에서 재번역해 준 어셈블리 코드를 잘 읽고, 기능과 역할을 도출하는 것"이다.

 

------------------------------------------------------------------------------------------------------------------------------

 

리버싱(분석) 방법

 

ⓐ 정적 분석(Static Analysis)

:: 파일을 실행하지 않고 파일의 겉모습을 관찰하여 분석하는 방법

  -- 파일의 종류, 크기, 헤더 정보(PE), Import/Export API, 내부 문자열, 실행 압축 여부, 등록 정보, 디버깅 정보, 디지털인증서 등의 다양한 내용을 확인할 수 있다.

  -- 디스어셈블러(ex; IDA)를 이용해 내부 코드와 구조를 확인할 수 있다.

 

==> 실행 파일을 구성하는 모든 요소, 대상 실행 파일이 실제로 동작할 CPU 아키텍처에 해당하는 어셈블리 코드를 이해하는 것이 필요

 

ⓑ 동적 분석(Dynamic Analysis)

: 파일을 실행시켜 행위를 분석하고, 디버깅하여 코드 흐름과 메모리 상태를 살펴보는 방법

  -- 파일, 레지스트리, 네트워크 등을 관찰하면서 프로그램의 행위를 분석한다.

  -- 디버거(ex; OllyDBG)를 이용하여 프로그램 내부 구조와 동작 원리를 분석한다.

 

==> 실행 단계별로 자세한 동작 과정을 살펴봐야 하므로, 환경에 맞는 디버거를 이용해 단계별로 분석하는 기술을 익혀야함

'Study > Reversing' 카테고리의 다른 글

main 함수 찾기  (0) 2021.03.23
OllyDBG, 어셈블리어  (0) 2021.02.04
IAT & EAT  (0) 2021.01.25
PE 헤더  (0) 2021.01.24
PE File Format 이해  (0) 2021.01.23

우리가 

신호등을 기다릴 수 있는 이유는

곧 바뀔 거라는 걸 알기 때문이다.

그러니 힘들어도 조금만 참자

 

곧 바뀔 거야

좋게

 

신호등처럼

 

 

 

 

「지쳤거나 좋아하는게 없거나」 中

'Think' 카테고리의 다른 글

마음과 말  (0) 2021.07.10
여행의 필요성  (0) 2021.01.31
혼자의 시간을 잘 보내는 방법  (0) 2020.11.04

1단계, simple_sqli 문제풀이

처음 들어갔을 때 나온 화면

 

 

로그인 화면
guest 입력 화면

아이디, 비밀번호에 guest를 입력하면 

 

 

hello guest가 alert로 뜨는 것 확인할 수 있다.

 

 

쿼리 문장(select * from users where userid="{userid}" and userpassword="{userpassword}")이 항상 참이 되게 하는 값을 넣어보았다. 

 

userid에는 admin" or "1

password 에는 1을 입력할 시 

쿼리문이

select * from users where userid="admin" or "1" and userpassword="1"

가 되어 userid가 admin인 경우가 항상 참(1)이된다.

 

위의 것으로 로그인 한 후의 화면

uid가 admin인 경우가 참(Truid가 admin인 경우가 참(True)이 되도록 설정합니다.ue)이 되도록 설정합니다

flag 입력

 

 

simple_sqli 문제 해결!

'WEB > WEB Hacking' 카테고리의 다른 글

Client-side Attack  (0) 2021.01.25
Flask, HTTP 요청 방식  (0) 2021.01.24
Dreamhack | 워게임 | <xss-1> 문제  (0) 2021.01.23
웹 해킹 기초  (0) 2021.01.23
Dreamhack | 워게임 | <cookie>문제  (0) 2020.11.19

1단계, cookie 문제풀이

처음 들어갔을 때 나온 화면이다.

 

 

소스 코드를 봤을 때, users 배열에는 guestadmin만 있기 때문에

 

 

guest와 admin 이외의 것을 입력하게 되면

 

 

not found user 가 뜨게 되는 것을 확인할 수 있었다.

 

 

 

그리고나서 guset로 로그인을 시도했고,

 

 

 

반가운 화면이 떴다.

 

 

 

F12를 눌러 EditThisCookie를 통해 cookie값을 변경한 후 새로고침을 하니, FLAG 값이 떴다.

 

 

 

 

cookie 문제 해결!

'WEB > WEB Hacking' 카테고리의 다른 글

Client-side Attack  (0) 2021.01.25
Flask, HTTP 요청 방식  (0) 2021.01.24
Dreamhack | 워게임 | <xss-1> 문제  (0) 2021.01.23
웹 해킹 기초  (0) 2021.01.23
Dreamhack | 워게임 | <simple_sqli>문제  (0) 2020.11.19

자바스크립트를 통해 할 수 있는 일 가운데 하나는 웹 브라우저를 제어하는 것이다.

첫 번째, style 에 들어가는 CSS문을 알 필요가 있고

두 번째, 스타일 속성을 주기 위해 그 속성을 가지고 있는 태그를 웹 브라우저에게 알리는 방법을 자바스크립트 문법으로 알아야 한다.

 

제어할 태그 선택하기

글쓴이는 만들고자 하는 웹 페이지에서 누르는 버튼에 따라 다르게 동작하도록 하고 싶다.

먼저 <input>태그로 버튼을 추가한다.

... 생략...  
  <input type="button" value="night">
  <input type="button" value="day">
  ...생략...

 

이 버튼을 클릭했을 때 이벤트가 필요하다.

따라서 onclick 속성을 추가한다.

...생략...
<input type="button" value="night" onclick="">
<input type="button" value="day" onclick="">
...생략...

 

이 버튼을 클릭했을 때 <body>태그에 style 속성을 동적으로, 프로그래밍적으로, 상호작용에 의해 넣으려고 한다.

그러기 위해서는 자바스크립트 문법에 따라 웹 브라우저에게 <body>태그를 선택하게 해야한다.

추천 검색어 ex) 'javascript select tag by css selector'

→ document.querySelector('body')

(여기서 괄호안에는 원하는 태그를 넣으면 된다. 클래스명이 'apple'이라면 document.querySelector(".apple")이라고 하면 되고, id값이 'target'이라면 document.querySelector('#target')이라 지정하면 된다.)

 

 

이제 선택했으니 <body>태그에 스타일 속성을 어떻게 자바스크립트로 넣을 수 있는지 알아봐야 한다.

추천 검색어 ex) 'javascript element style' 

이를 참고해 document.querySelector('body').style 이라고 작성한다.

 

추천 검색어 ex) 'javascript style background-color'

이를 참고해 document.querySelector('body').style.backgroundColor = 'black'; 이라고 작성한다.

...생략...
    <input type="button" value="night" onclick="
    	document.querySelector('body').style.backgroundColor='black';
        document.querySelector('body').style.color='white';">
    <input type="button" value="day" onclick="
    	document.querySelector('body').style.backgroundColor='white';
    	document.querySelector('body').style.color='black';">
...생략...

 

최종적으로 작성한 코드이다. 

이렇게 사용자와 상호작용해서 HTML과 CSS를 동적으로 변경하는 방법을 알게 되었다.

 

 

조건문 활용

...생략...
<input id="night_day" type="button" value="night" onclick="
    if (document.querySelector('#night_day').value === 'night'){
      document.querySelector('body').style.backgroundColor='black';
      document.querySelector('body').style.color='white';
      document.querySelector('#night_day').value = 'day';
    } else {
      document.querySelector('body').style.backgroundColor='white';
      document.querySelector('body').style.color='black';
      document.querySelector('#night_day').value = 'night';}
">
  ...생략...

 

if else를 활용한 코드이다.

참고) === 는 좌항과 우항을 비교하는 비교연산자. 결과로 TRUE와 FALSE 가 나온다.

[if] id가 night_day인 태그의 value가 night 라면 배경색을 black로, 글자색을 흰색으로, value 값을 day로 바꾼다.

[else] 그것이 아니라면(value가 day라면) 배경색을 white로, 글자색을 검정색으로, value 값을 night로 바꾼다.

 

 

중복의 제거를 위한 리팩터링

코드의 가독성을 높이고, 유지보수를 편리하게 만들고, 중복된 코드를 줄이는 방향으로 코드를 개선하는 작업을 리팩터링(refactoring)이라 한다.

 

...생략...
    <input type="button" value="night" onclick="
    var target = document.querySelector('body');
    if (this.value === 'night'){
      target.style.backgroundColor='black';
      target.style.color='white';
      this.value = 'day';
    } else {
      target.style.backgroundColor='white';
      target.style.color='black';
      this.value = 'night';}
      ">
...생략...

앞서 작성했던 코드의 리팩터링 후 모습이다.

input 태그 안의 id를 삭제한 후

document.querySelector('#night_day')를 this (onclick과 같은 이벤트 안에서 실행되는 코드에서 현재 코드가 속해 있는 태그를 가리키도록 약속돼있는 특수한 키워드)로,

반복되는 body 태그 document.querySelector('body')를 target 으로 변경하였다.

 

 

배열과 반복문의 활용

야간 모드일 때는 링크들이 밝게 표시되고, 주간 모드일 때는 다소 어두운 계열로 링크가 표시되게 완성해 보자.

...생략...
    <input type="button" value="night" onclick="
    var target = document.querySelector('body');
    if (this.value === 'night'){
      target.style.backgroundColor='black';
      target.style.color='white';
      this.value = 'day';

      var alist = document.querySelectorAll('a');
      var i = 0;
      while(i < alist.length){
        alist[i].style.color = 'powderblue';
        i = i + 1;
      }
    } else {
      target.style.backgroundColor='white';
      target.style.color='black';
      this.value = 'night';

      var alist = document.querySelectorAll('a');
      var i = 0;
      while(i < alist.length){
        alist[i].style.color = 'blue';
        i = i + 1;
      }
    }
      ">
...생략...

위 코드는 <a>태그에 있는 글자들을 찾아(var alist = document.querySelectorAll('a');) 배열과 반복문을 활용해서 글씨를 바꿔준(alist[i].style.color = 'blue';) 예시다.

 

 

함수의 활용

동작하는 내용은 똑같지만 코드를 효율적으로 만드는 것을 리팩터링이라고 했다.

...생략...
 <head>
    ...생략...
    <script>
      function nightDayHandler(self){
        var target = document.querySelector('body');
        if (self.value === 'night'){
          target.style.backgroundColor='black';
          target.style.color='white';
          self.value = 'day';

          var alist = document.querySelectorAll('a');
          var i = 0;
          while(i < alist.length){
            alist[i].style.color = 'powderblue';
            i = i + 1;
          }
        } else {
          target.style.backgroundColor='white';
          target.style.color='black';
          self.value = 'night';

          var alist = document.querySelectorAll('a');
          var i = 0;
          while(i < alist.length){
            alist[i].style.color = 'blue';
            i = i + 1;
          }
        }
      }
    </script>
  </head>

  <body>
    ...생략...
    <input type="button" value="night" onclick="nightDayHandler(this)">
...생략...

함수를 만들어 <head>태그 안에 넣어줬다.

원래 onclick 이벤트 안에서 this는 onclick 이벤트가 소속되어 있는 input 태그를 가리키도록 약속되어 있는데, 

독립되어 있는 함수를 만들면 원래의 this는 더 이상 input 버튼이 아니고, 전역객체(윈도우)를 가리키게 된다.

 

따라서 함수는 매개변수를 self로 받고, 함수를 실행할 때는 this를 매개변수로 넣어 input 버튼을 가리키도록 했다.

이렇게 함으로써 코드의 효율성이 크게 증가한다.

 

 

객체의 활용

서로 연관된 함수와 서로 연관된 변수를 같은 이름으로 그룹핑하기 위한 도구를 객체라고 생각하면 쉽다.

객체에 소속된 함수메서드라고 하며, 객체에 소속된 변수프로퍼티라 한다.

...생략...
    <script>
      var Body ={
        setColor: function(color){
          document.querySelector('body').style.color = color;
        },
        setbackgroundColor: function(color){
          document.querySelector('body').style.backgroundColor = color;
        }
      }
      var Links = {
        setColor: function(color){
          var alist = document.querySelectorAll('a');
          var i = 0;
          while(i < alist.length){
            alist[i].style.color = color;
            i = i + 1;
          }
        }
      }

      function nightDayHandler(self){
        var target = document.querySelector('body');
        if (self.value === 'night'){
          Body.setbackgroundColor('black');
          Body.setColor('white');
          self.value = 'day';
          Links.setColor('powderblue');
        } else {
          Body.setbackgroundColor('white');
          Body.setColor('black');
          self.value = 'night';

          Links.setColor('blue');
        }
      }
    </script>
  </head>
...생략...

주의할 점 : 객체에서는 프로퍼티와 프로퍼티를 구분하기 위해 콤마를 사용해야 한다.

 

 

파일로 쪼개서 정리 정돈 하기

<script>태그에 있는 내용들을 다른 웹 페이지에서도 구현하고 싶다.

따라서 <script>태그 안에 있는 내용을 따로 color.js라는 자바스크립트 파일로 저장한 뒤, 웹 페이지에서 링크를 불러올 거다.

↓color.js 코드

  var Body ={
    setColor: function(color){
      document.querySelector('body').style.color = color;
    },
    setbackgroundColor: function(color){
      document.querySelector('body').style.backgroundColor = color;
    }
  }
  var Links = {
    setColor: function(color){
      var alist = document.querySelectorAll('a');
      var i = 0;
      while(i < alist.length){
        alist[i].style.color = color;
        i = i + 1;
      }
    }
  }

  function nightDayHandler(self){
    var target = document.querySelector('body');
    if (self.value === 'night'){
      Body.setbackgroundColor('black');
      Body.setColor('white');
      self.value = 'day';
      Links.setColor('powderblue');
    } else {
      Body.setbackgroundColor('white');
      Body.setColor('black');
      self.value = 'night';

      Links.setColor('blue');
    }
  }

↓본문에서의 사용

  <head>
    ...생략...
    <script src="color.js"></script>
    ...생략...
  </head>

이렇게 작성한 코드를 재사용하게 되는 것이며, color.js 파일을 수정하면 모든 웹 페이지에 동시에 변화가 반영이 된다.

가독성이 좋아지고, 코드가 훨씬 명확해지며, 코드의 의미를 파일의 이름을 통해 확인할 수 있게 된다.

그리고 이렇게 하면 좋은 점이 또 있다.

웹 페이지를 로드하면서 웹 페이지에 접속해서 자바스크립트 파일도 다운로드 해야하므로 2번 접속해야 한다. 웹 서버 입장에서는 나쁜 일이다. 그럼에도 이렇게 하는 게 훨씬 더 효율적이다. 왜냐하면 캐시 때문이다.

캐시는 '저장한다'는 의미인데, 한 번 웹 페이지에서 다운로드된 파일은 웹 브라우저가 보통 컴퓨터에 저장해놓는다. 따라서 다음에 접속할 때 저장된 파일을 읽어서 네트워크를 통하지 않게 한다. 서버 입장에서 훨씬 더 비용을 절감할 수 있고, 사용자 입장에서도 네트워크 트래픽을 절감할 수 있으며, 훨씬 더 빠르게 웹 페이지를 화면에 표시할 수 있다는 효과가 생기기 때문에 이렇게 파일로 쪼개는 것이 좋은 방법이다. 

 

 

 

 

 

위 글은 「생활코딩! HTML+ CSS + 자바스크립트」의 내용을 참고하여 작성한 글입니다.

'WEB > JavaScript' 카테고리의 다른 글

Open API 활용  (0) 2021.05.02
라이브러리 & 프레임워크  (0) 2021.01.27
콘솔  (0) 2020.11.05
이벤트  (0) 2020.11.05
JavaScript 시작, <script> 태그  (0) 2020.11.05

미분

미분은 '특정 순간'의 변화량이며, 수식은 다음과 같다.

함수의 미분

이는 결국 x의 '작은 변화'가 함수 f(x)를 얼마나 변화시키느냐를 의미한다. 

이때 시간의 작은 변화, 즉 시간을 뜻하는 h를 한없이 0에 가깝게 한다는 의미를 lim h->0 로 나타낸다.

 

# 나쁜 구현 예
def numerical_diff(f,x):
    h = 10e-50 # 작은 값. 이 방식은 결국 반올림 오차 문제를 일으키게 된다.
    return (f(x+h) - f(x)) / h

함수 f의 차분 문제도 있다. 

'진정한 미분'x 위치의 함수의 기울기(접선)에 해당하지만, 이번 구현에서의 미분은 (x+h)와 x 사이의 기울기에 해당한다.

 

def numerical_diff(f,x):
    h = 1e-4 #0.0001
    return (f(x+h) - f(x-h)) / (2*h)

문제점들을 해결한 코드이다.

 

 

편미분

여기선 변수가 2개이기 때문에 '어느 변수에 대한 미분이냐', 즉 x0과 x1 중 어느 변수에 대한 미분이냐를 구별해야 한다.

편미분은 변수가 하나인 미분과 마찬가지로 특정 장소의 기울기를 구한다. 

단, 여러 변수 중 목표 변수 하나에 초점을 맞추고 다른 변수는 값을 고정한다. 

 

 

위 글은 「밑바닥부터 시작하는 딥러닝」을 참고하여 작성한 글입니다.

'Study > Deep Learning' 카테고리의 다른 글

머신러닝 Data 종류  (0) 2021.10.14
머신러닝 기본 프로세스  (0) 2021.10.14
딥러닝의 응용분야  (0) 2021.10.13
머신러닝/딥러닝 기초  (0) 2021.10.13
신경망 학습  (0) 2020.11.06

+ Recent posts