- 18
- Hanam09
- 조회 수 1795
안녕하세요 beautifulSoup를 사용하려하는 파이썬 생초보입니다
beautifulSoup 로 네이버에 로그인을하려 하는데 잘 안되네요.. 암호화 과정에서 막힙니다.
python의 rsa모듈을 사용하여 패스워드를 암호화 하려 했으나 Encrypt함수에서 막히네요.. 무엇이 문제일까요?
도무지 감이 오지 않네요..
import lzstring, requests, rsa, json from bs4 import BeautifulSoup headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36", 'Content-type': 'application/x-www-form-urlencoded' } USER_ID = input("Input ID:") USER_PW = input("Input PW:") _uuid = "6b84566b-c8d2-420e-b87c-f45357a233d0-4" LOGIN_FORM = { "localechange": "", "enctp": "1", "svctype": "1", "smart_LEVEL": "1", "locale": "KO_KR", "id": "", "pw": "", "bvsd": { "uuid": _uuid, } } LOGIN_BVSD_ENCDATA_AS_PLAIN = { "a":_uuid, "b":"1.3.4", "d":[ { "i":"id", "b":{ "a":[ "0,program1472" ] }, "d":"program1472", "e":False, "f":False }, { "i":"pw", "e":True, "f":False } ], "h":"1f", "i":{ "a": headers["User-Agent"] } } with requests.Session() as window: request = window.get("https://nid.naver.com/login/ext/keys.nhn") #키를 가져와 keys = request.text #keys 변수에 넣고 keysAsArrayElement = keys.split(",") # js 분석결과가 첫번째부처 Sessionkey, keyname, epub , npub 이다 LOGIN_FORM["encnm"] = keysAsArrayElement[1] info = chr(len(keysAsArrayElement[0])) + keysAsArrayElement[0] + chr(len(USER_ID)) + USER_ID + chr(len(USER_PW)) + USER_PW rsaKey = rsa.PublicKey(int(keysAsArrayElement[2],16),int(keysAsArrayElement[3],16)) LOGIN_FORM["encpw"] = rsa.encrypt(info,rsaKey) # 문제있는 부분 bvsdEncoder = lzstring.LZString() LOGIN_FORM["bvsd"]["encData"] = bvsdEncoder.compressToBase64(json.dumps(LOGIN_BVSD_ENCDATA_AS_PLAIN)) LOGIN_FORM["bvsd"] = json.dumps(LOGIN_FORM["bvsd"]) print(json.dumps(LOGIN_FORM)) # res = window.post("https://nid.naver.com/nidlogin.login", data=LOGIN_FORM, headers=headers)
작성자
댓글 18
답변해주셔서 정말로 감사합니다.
다시한번 JS부분을 분석해 봤더니 RSA암호화 방식과 python의 rsa암호화 방식과 약간의 차이가 있는것 같군요.
spidermonkey를 활용하면 쉽게 로그인되겠죠..
참, 또 한가지 질문이 있는데
Selenium의 send_keys 메서드를 막아놓는 방법이 있다면 Javascript를 사용하면 되지 않나요?
옙 저도 파이썬 웹크롤링의 초보이지만 Spidermonkey를 이용하여 결국 해결이 되셨다니 다행이네요~
저는 같은 명칭의 RSA라서 같은 방식일 줄 알았는데 암호화 방식의 차이가 있었군요 ㅎㄷㄷ
아쉽게도 파이썬용 Spidermoneky가 depricated 되었으니 앞으로는 성격이 좀 다르긴 하지만 ghost.py 같은 라이브러리를 사용해야 될까요?
Selenium에서 send_keys() 메서드를 막아놓은 경우에는 말씀하신대로 자바스크립트를 이용할 수도 있습니다.
제가 지난달에 적었던 글인데요~
https://studyforus.com/study/584242
1) 자바스크립트를 이용하는 방법
2) PyAutoGUI 또는 Pyperclip 등 클립보드 관련 라이브러리를 이용하는 방법
3) 다른 라이브러리를 사용하지 않고 Selenium에서 ActionChains 또는 send_keys()로 ctrl + c, v를 하는 방법 등이 있겠죠.
그런데 제가 테스트했던 일부 사이트에서는 1)번 방법은 통하지 않았더군요.
제가 뭔가 실수한 것일수도 있겠지만, 이 방법도 어느 정도 널리 알려진 방법이라서 그런지 창과 방패의 싸움 같아요 ㅠㅠ
Stackoverflow에서도 1)번 방법이 막혀서 안 되는 경우가 있다는 여러 리플들을 확인했어요.
Selenium을 탐지하는 방법이 여러가지가 있다고는 하던데,
구체적으로 어떤 방법으로 1)번을 막았는지에 대해서는 제가 JS 파일을 뜯어본 것도 아니고, 실력도 부족해서 솔직히 잘 모르겠습니다.
저는 윈도우에서는 클립보드 관련 라이브러리로 해결하는 경향이 있고, 여러 사이트에서 대체로 이 방법이 잘 통하는 것 같더군요 :)
(이렇게 한 번 작성한 스크립트가 있어서 여러 사이트에서 이런 방식으로 해결하는 것이고, 네이버에서 자바스크립트를 막았는지 확인하지는 않았어요)
Headless 브라우저나 우분투에서 Selenium을 사용하려면 말씀하신대로 자바스크립트를 이용하는 방법이 가장 확실한 것 같습니다.
다만 --user-data-dir을 지정하지 않으면 다른 방식으로 인증을 요구하는 사이트들은 골치가 아프네요 ㅠㅠ
Selenium을 통한 네이버 로그인에 대해 더 궁금하시다면 비교적 최근에 작성된 아래의 글을 참고하세요~
1) https://medium.com/@zective/selenium-%EB%84%A4%EC%9D%B4%EB%B2%84-%EB%A1%9C%EA%B7%B8%EC%9D%B8%EC%8B%9C-%EC%BA%A1%EC%B1%A0-%ED%8C%A8%EC%8A%A4-11221379b661
2) https://hyrama.com/?p=693
그럼 좋은 주말 되세요!
감사합니다.
덕분에 궁금증이 해결되었습니다!
RSA 모듈의 경우는 모르겠지만 pycryptodome 의 경우에는 차이 없이 잘 동작합니다..
참고로 RSA 암호화의 특징 상 랜덤으로 값을 설정하는 부분이 있어서 암호화를 할 때마다 값이 달라집니다.
네이버의 경우 추가로 확인해본 결과 키보드 입력 타이밍과 마우스 이동에 대한 내용을 같이 포함해서 전달하도록 해서 봇인지 여부를 체크하는 식으로 되어 있습니다.
오오~ 궁금했던 부분인데 설명해주셔서 감사합니다!
말씀해주신대로 네이버 로그인을 할 때 키보드 입력 타이밍과 마우스 이동까지 체크한다면,
selenium을 사용하지 않고 requests 라이브러리로 로그인을 하는 것은 제 실력으로는 불가능하겠네요 ㅎㄷㄷ
혹시 selenium에서 특정 element를 클릭하는 것도 말씀하신 '마우스 이동'에 해당하는지 여쭤봅니다.
(예컨대 driver.find_element_by_xpath("XPATH").click() 하는 것이요)
오토핫키의 경우에는 1) mousemove(x, y)를 한 후에 mouseclick(left, x, y)를 하는 것과
2) 그냥 mouseclick(left, x, y)을 하는 것이 전혀 다르고, 화면상으로도 다른 방식으로 작동하더군요.
(두 번째 방법으로 하면 순간적으로 마우스 커서가 사라졌다가 x, y 위에서 다시 나타나던데요.)
그럼 humit 님께서도 굿밤 되시고 8월의 마지막 한 주도 화이팅이요~!
항상 감사드립니다 ^-^
+)
마우스와 키보드를 체크한다면 Lastpass 등 확장프로그램을 이용하여 자동 로그인을 하는 경우에는
마우스 클릭이나 키보드 타이핑을 하지 않으니 혹시 문제가 생기지는 않는가요??
일단 클릭하지 않더라도 move_by_offset 함수만 사용하더라도 움직임이 로깅이 됩니다. 그런데 마우스 움직임의 경우에는 체크를 하는 경우도 있고 하지 않는 경우도 있는 것 같긴 하더라고요.. 실제로 selenium에서 마우스 이동을 시키지 않더라도 로그인이 잘 동작하였습니다.
아마 키보드 입력의 주기 등을 고려해서 전체적으로 확인하는 것 같더라고요.
오토핫키의 경우에는 제가 써보질 않아서 답변을 드릴 수가 없겠네요...
Lastpass 확장프로그램은 써보질 않아서 잘 동작하는지 여부는 모르겠네요...
앗 감사합니다 ^-^
Selenium에서 마우스 이동으로 하지 않더라도 키보드 입력주기 등을 고려하여 로그인이 가능하군요~
하긴 일상생활에서도 마우스가 고장나면 극단적으로 탭키를 이용하여 input element로 이동하여 로그인을 하는 사람도 있을테니깐요 ㄷㄷ
제가 오토핫키를 예로 들었지만 파이썬 selenium의 경우에도 mouseMove() 메서드와 click() 메서드가 있으니
아마도 비슷하지 않을까 생각되어서요~
제가 여쭤본 것은 네이버 로그인 자체가 궁금하기도 했지만
그누보드에서 비슷한 방식으로 requests와 selenium을 이용한 글 작성을 막아보려고 했거든요.
Lastpass 같은 자동 로그인 프로그램이 허용되면서 requests와 selenium만 막는 방법을 찾으려니 쉽지 않네요 ㅠㅠ
이 부분에 대해 저도 더 공부할게요~
그럼 굿밤 되세요! 다시 한 번 감사드립니다~
안타깝게도 requests나 selenium을 막을 수 있는 방법은 없습니다. 극단적으로 사람이 실제로 입력하는 것과 똑같은 방식으로 흉내내게 하면 서버 측에서는 알 수 있는 방법이 없으니까요..
실제로 네이버 로그인의 경우에도 requests와 selenium 모두 로그인을 할 수 있습니다.
입력된 글자 수와 글을 작성하는데 걸리는 시간을 측정하여 그 비율을 계산해 봇을 탐지하는 식으로 가는게 그나마 가능한 구현 방법일 것 같네요. 해당 방식의 경우 CSRF 토큰을 발급해주는 부분에서 CSRF 토큰과 발급한 시간을 매칭시켜서 저장을 시킨 다음에 실제로 폼이 제출이 되었을 때 제출된 시간과 CSRF 토근이 발급된 시간을 체크하는 식으로 구현하시면 되겠습니다. 그래서 너무 시간이 짧다면 캡챠를 입력하도록 창을 띄워주는 식으로 하면 되겠네요. (구글 Captcha와 유사한 방식)
이렇게 한다면 Ctrl + C, Ctrl + V로 글을 무자비로 등록하는 것도 막을 수 있고 봇을 통한 입력을 어느 정도 걸러낼 수 있다는 점이 있겠습니다.
옙 잘 알겠습니다! ^^ 감사합니다~
봇에 의한 글 작성을 100% 전적으로 막기 어렵더라도, 그누보드 용도로 제작된 범용(?) 봇이라도 막아보려구요 ㅠㅠ
네이버 로그인 같은 경우에는 pypi에도 관련 라이브러리가 있고, 많은 블로그와 유튜브 영상이 있지만
적어도 제가 구글링했던 방법들은 최근에는 모두 막힌 것 같더군요 ㅜㅜ
네이버 수준까지는 아니더라도 어느 정도 수준에서 봇을 detect해서 막아보고 싶거든요.
아마도 실용성은 그다지 없겠지만,
저는 자바스크립트 모달 로그인을 이용해서 requests를 이용한 범용 봇을 어느 정도 선에서 막고
아직 구체적인 아이디어는 없지만 마우스 이동을 탐지하는 방법으로 selenium을 막아보려고 했거든요.
물론 봇 제작자가 마음을 독하게 먹으면 오토핫키로 실제 브라우저를 띄우고 마우스를 이동해서 로그인하여 글을 작성하겠지만요 ㄷㄷ
말씀하신대로 입력된 글자 수와 소요된 시간을 비교하는 방법이 현실적으로 가능성이 있겠네요.
물론 극단적으로 time.sleep을 적절히 사용하면 이것도 뚫리겠지만요 T.T
그럼 안녕히 주무세요! 다시 한 번 감사드립니다~
아.... 그래서 암호화후에 값이 common.js의 rsa암호화값이랑 달랐던건가...
한번해보겠습니다.
그리고 봇 체크여부는 네이버에 전달되는 타이밍 값을 흉내내서 전달하면 되는 문제인것 같네요..
감사합니다.
+ 추가로 _uuid 부분도 이전에 사용한 값인지 체크하는 로직도 있는 것으로 보이더라고요. uuid 부분을 같게 해서 요청을 보내면 캡챠 부분에 걸립니다.
아 그럼 랜덤으로 생성해야겠군요...
BVSD가 웹팩 + 난독화되있어서 파이썬 이식에 어려움을 겪어서..
감사합니다.
팁을 드리자면 breakpoint를 적절하게 사용하시고 추가로 fingerprint.js를 내부적으로 사용하고 있다 정도의 힌트를 드립니다.
감사합니다!
TypeError: sequence item 3: expected a bytes-like object, str found
확인해보니 이런 에러가 뜨네요.
https://stuvel.eu/python-rsa-doc/reference.html#rsa.encrypt
공식문서를 보면 string이 아니라 bytes를 넣어야 된다고 나오네요.
rsa.encrypt(message: bytes, pub_key: rsa.key.PublicKey)
문제가 된다고 말씀하신 부분은 다음과 같이 수정하시면 됩니다 ^^
LOGIN_FORM["encpw"] = rsa.encrypt(info.encode(), rsaKey)
그런데 이 부분을 해결해도 로그인은 실패하고, 'content-type'을 변경해도 역시 안 되네요 ㅠㅠ
요새는 Selenium으로 네이버 로그인을 시도해도 send_keys() 메서드를 막아놓아서 클립보드에서 복붙해야 되고
캡챠가 뜨는 경우가 많아서 --user-data-dir을 지정해야 되는 경우가 있던데 정말 어렵네요~