폼과 로그인 뚫기

Koo·2023년 8월 21일
post-thumbnail
  • 로그인 없이 얻을 수 있는 정보들은 HTTP GET을 써서 요청 가능
  • 웹 서버에서 저장하고 분석할 정보를 보내는 HTTP POST를 사용 가능
  • Form이란?
    • 웹 서버가 이해하고 사용할 수 있는 POST 요청을 사용자가 보낼 수 있게 하는 수단
    • link tag - GET 요청을 형식에 맞게 보낼 수 있도록 도움
    • POST form - POST 요청을 형식에 맞게 보낼 수 있도록 도움
  • 최신 웹사이트의 HTML 폼은 즉시 드러나지 않는 보안 기능(자동 가입 방지 문자, 이미지 선택 등)이 포함되는 경우가 많음
    • 이런 보안 기능을 처리하기 위해서는 이미지 처리나 텍스트 인식 등에 대한 이해가 필요

Python request 라이브러리

  • urllib과 GET 요청 이상의 것을 수행하기 위해서는 기본 라이브러리로는 한계가 존재
  • python의 request 라이브러리를 사용하면 복잡한 HTTP 요청과 쿠키, 헤더를 쉽게 처리 가능

기본적인 폼 전송

  • 폼은 ⅰ) HTML 필드와 ⅱ) 전송 버튼, ⅲ) 실제 처리하는 액션 버튼으로 구성
  • 유명한 사이트들은 대부분 robots.txt 파일에서 로그인 폼에 접근하는 것을 거부
  • 기억해야 할 점
    - 데이터를 전송할 필드 이름
    - 
    ex) 폼 예시
<form method="post" action="processing.php">
  First name: <input type="text" name="firstname"><br>
  Last name: <input type="text" name="lastname"><br>
  <input type="submit" value="submit">
</form>
  • input의 name은 폼을 전송할 때 POST로 서버에 전달될 변수 이름을 결정
  • 폼이 실제로 동작하는 곳은 processing.php
  • 폼에 POST 요청을 보낼 때는 폼 자체가 있는 페이지가 아닌 processing.php로 보내야 한다
  • 폼의 목적은 웹사이트 방문자가 실제 동작을 수행하는 페이지에 올바른 형식으로 요청을 보내도록 돕는 것
import requests

params = {'firstname': 'Ryan', 'lastname': 'Mitchell'}
r = requests.post('http://pythonscraping.com/files/processing.php', data=params)
print(r.text)

라디오 버튼, 체크박스, 기타 필드

  • 웹 폼에는 텍스트 필드와 전송 버튼뿐만 아니라 라디오 버튼, 체크박스, 셀렉트 박스 등 수 많은 필드가 존재
  • javascript를 사용하면 쓸 수 있는 필드가 무한히 늘어나게 된다
  • 폼 필드가 복잡해도 필드 이름과 값만 신경 쓰면 된다
  • 입력 필드의 값 형식을 확신할 수 없다면 브라우저가 사이트와 주고받는 GET, POST 요청을 추적하는 여러도구를 사용 가능
    • URL을 직접 읽어보거나
    • 개발자 도구를 사용

로그인과 쿠키 처리

  • 단순히 폼을 전송하여 필요한 정보를 받는 경우, 로그인 상태를 유지하는 기능이 없음
  • 최신 웹 사이트는 대부분 쿠키를 사용해 로그인한 정보를 추적
    • 로그인 요청을 인증하면, 사이트는 브라우저에 쿠키를 저장
    • 쿠키에는 서버에서 생성한 토큰, 만료일, 추적(tracking) 정보를 포함
    • scraper로 언제든 로그인 할 수 있지만, 서버가 반환하는 쿠키를 활용하지 못하면 웹 사이트는 로그인되어 있지 않다고 판단
import requests

params = {'username': 'koo', 'password': 'password'}
r = requests.post('https://pythonscraping.com/pages/cookies/welcome.php',
	params)
print('Cookie is set to', r.cookies.get_dict()) # {'loggedin': 1, 'username': 'koo'}
print('-' * 20)
print(Going to profile page...')

r = requests.get('https://pythonscraping.com/pages/cookies/profile.php')
print(r.text) # Hey koo! Looks like you're still logged into the site!

이런 방법은 단순한 상황에서는 잘 작동하지만, 복잡한 사이트는 경고 없이 자주 쿠키를 수정하기도 하고, 쿠키에 대해 생각하지 못하고 코드를 작성할 수도 있음
→ requests의 session 함수를 사용하면 이러한 문제를 해결 가능

import requests

session = requests.Session()
params = {'username': 'koo', 'password': 'password'}
s = session.post('https://pythonscraping.com/pages/cookies/welcome.php', params)

print('Cookie is set to: ', s.cookies.get_dict())
print('-' * 20)
print('Going to profile page...')
s = session.get('https://pythonscraping.com/pages/cookies/profile.php')
print(s.text)
  • requests의 Session은 가져온 세션 객체가 쿠키나 헤더, HTTPAdapters와 같은 HTTP에서 동작하는 프로토콜에 관한 정보까지 세션 정보를 관리
  • web scraper를 만들 때는 항상 쿠키가 어떤 모양이고 무슨 일을 하는지 파악하는 것이 대단히 중요

HTTP 기본 접근 인증

  • 쿠키가 등장하기 전에 가장 많이 쓰이던 로그인 처리 방법은 HTTP 기본 접근 인증(basic access authentication)
  • requests의 auth 모듈을 사용하면 HTTP 인증을 처리할 수 있다
import requests
from requests.auth import AuthBase, HTTPBasicAuth

auth = HTTPBasicAuth('koo', 'password')
r = requests.post(url='https://pythonscraping.com/pages/auth/login.php', auth=auth)
print(r.text)

HTTPBasicAuth 객체를 auth 매개변수로 요청에 넣어 처리

profile
스터디를 해보자

0개의 댓글