본문 바로가기
ETC/Python

Naver Login with Python requests 2(소스코드)

by Guardy 2020. 7. 9.
728x90

이번 글에서는 Naver Login을 완성시킬 예정이다.
저번글 보기

encpw는 16진수이기때문에 rsa.encrypt 후 hex()를 사용하여준다.

완성된 encrypt function은 다음과 같다.

def encrypt(naver_id, naver_pw):
    key_str = requests.get('https://nid.naver.com/login/ext/keys.nhn').content.decode("utf-8")
    sessionkey , Keyname, evalue, nvalue = key_str.split(',') 
    evalue, nvalue = int(evalue, 16), int(nvalue, 16)
    pubkey = rsa.PublicKey(evalue, nvalue)
    message = [sessionkey,naver_id,naver_pw]
    merge_message = ""
    for s in message:
        merge_message = merge_message + ''.join([chr(len(s)) + s])
    merge_message = merge_message.encode()
    encpw = rsa.encrypt(merge_message, pubkey).hex()
    return Keyname, encpw

encpw를 했으니 이번 글은 bvsd를 완성시켜서 값을 보낼 차례이다.

bvsd는 우선 uuid와 encData로 이루어져있다.

uuid는 컴퓨터네트워크주소와 현재시간으로 UUID를 생성하는 것이다.

파이썬 라이브러리에 uuid가 있기 때문에 import해서 사용해주면된다.

encdata만 해결하면되는데 https://nid.naver.com/login/js/bvsd.1.3.4.min.js에 단서가 있었다.

encdata는 r이다.

n = s.stringify({
                    uuid: e.a,
                    encData: r
                })

uuid는 e.a고 encData는 r이다.

r은  r = i["default"].compressToEncodedURIComponent(o)라고 한다.

그럼 o를 찾아야 한다.

o는 다음과 같다.

o = {
                        a: n,
                        b: "1.3.4",
                        c: (0, m["default"])(),
                        d: r,
                        e: this._deviceOrientation.get(),
                        f: this._deviceMotion.get(),
                        g: this._mouse.get(),
                        j: this._fpDuration || _.NOT_YET,
                        h: this._fpHash || "",
                        i: this._fpComponent || []
};

 

 

이를 파이썬 코드로 고친다 a b h i만 써도 작동하는 것을 확인

o = '{"a":"' + str(bvsd_uuid) + '","b":"1.3.4","h":"1f","i":{"a":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Whale/2.7.100.20 Safari/537.36"}}'  
encData = lzstring.LZString.compressToEncodedURIComponent(o)
bvsd = '{"uuid":"'+ bvsd_uuid + '","encData":"'+ encData +'"}'

compressToEncodedURIComponent는 파이썬 라이브러리 lsztring에 있어서 import하여 사용하면 된다.

여기까지 했으면 진짜 다 끝났다.

 

requests를 위해 session과 header를 만들어준다.

session = requests.Session()
headers = {
	'User-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Whale/2.7.100.20 Safari/537.36'
}

보낼 data를 만들어준다.

data = {
        'enctp': '1',
        'svctype': '0',
        'encnm': encnm,
        'locale' : 'ko_KR'
        'url': 'www.naver.com',
        'smart_level': '1',
        'encpw': encpw,
        'bvsd': bvsd
}

data 순서는 상관없다.

resp에 post한 값을 받는다.(로그인이 정상적으로 되었는지 확인하기 위함)

resp = session.post('https://nid.naver.com/nidlogin.login', data=data, headers=headers)
print(resp.text)

만약 결과가 다음과 같이 나왔으면 정상적으로 된것이다.

<html>
  <script language=javascript nonce="kj7t7znEI0SQBDdvp5LOP4T0">
  	location.replace("https://nid.naver.com/signin/v3/finalize?url=https%3A%2F%2Fwww.naver.com&svctype=1");
  </script>
</html>

네이버 로그인은 최종적으로 해당 주소로 이동해야하기 때문에 파싱을 통해 주소를 가져온다.

마지막으로 get을 이용해 해당 주소로 이동하면 된다.

login_url = resp.text.split('("')[1].split('"')[0]
session.get(login_url)

로그인 성공 실패를 보여주기 위해서 다음과 같이 수정할 수 있다.

 resp = session.post('https://nid.naver.com/nidlogin.login', data=data, headers=headers)
 if(resp.text.find("location")>-1):
 	print("로그인 성공")
 	login_url = resp.text.split('("')[1].split('"')[0]
 	session.get(login_url)
else:
	print("로그인 실패")

완성 코드

import re
import requests
import lzstring
import uuid
import rsa

def encrypt(naver_id, naver_pw):
    key_str = requests.get('https://nid.naver.com/login/ext/keys.nhn').content.decode("utf-8")
    sessionkey , Keyname, evalue, nvalue = key_str.split(',') 
    evalue, nvalue = int(evalue, 16), int(nvalue, 16)
    pubkey = rsa.PublicKey(evalue, nvalue)
    message = [sessionkey,naver_id,naver_pw]
    merge_message = ""
    for s in message:
        merge_message = merge_message + ''.join([chr(len(s)) + s])
    merge_message = merge_message.encode()
    encpw = rsa.encrypt(merge_message, pubkey).hex()
    return Keyname, encpw

def naver_login(nid, npw):
    encnm, encpw = encrypt(nid, npw)
    bvsd_uuid = uuid.uuid4()
    o = '{"a":"' + str(bvsd_uuid) + '","b":"1.3.4","h":"1f","i":{"a":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Whale/2.7.100.20 Safari/537.36"}}'  
    encData = lzstring.LZString.compressToEncodedURIComponent(o)
    bvsd = '{"uuid":"'+ str(bvsd_uuid) + '","encData":"'+ encData +'"}'
    session = requests.Session()
    headers = {
        'User-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Whale/2.7.100.20 Safari/537.36'
    }
    data = {
        'enctp': '1',
        'svctype': '0',
        'encnm': encnm,
        'locale' : 'ko_KR',
        'url': 'www.naver.com',
        'smart_level': '1',
        'encpw': encpw,
        'bvsd': bvsd
    }
    resp = session.post('https://nid.naver.com/nidlogin.login', data=data, headers=headers)
    if(resp.text.find("location")>-1):
        print("로그인 성공")
        login_url = resp.text.split('("')[1].split('"')[0]
        session.get(login_url)
    else:
        print("로그인 실패")


if __name__ == "__main__":
    naver_login(네이버 아이디, 네이버 비밀번호)

2020-07-09 현재 정상 작동하는 것을 확인할 수 있다.

 

ps. js 파일이 min으로 되어있는 경우 분석하기 매우 복잡하여 https://beautifier.io/사이트를 이용했더니 가독성이 좋다.

 

#교육 및 학습목적으로 작성된 자료입니다. 악용 및 배포를 금지합니다.#

728x90