- 11
- 이니스프리
- 조회 수 1025
안녕하세요?
요새 CSRF 토큰 로그인이 클리앙을 비롯한 많은 사이트에서 사용되고 있고
스포어 회원님들의 사이트를 보더라도 적용하신 분들이 많더군요 ^^
다만 아쉽게도 그누보드 계열에서는 아직 사용하지 않는 것 같더군요.
그래서 대략 다음과 같은 방법으로 CSRF 토큰 로그인을 구현을 해보려고 하는데요.
제가 보안에 대해서 잘 알지 못하고, 세션을 잘 다루지도 못해서 이러한 방식이 맞는지 모르겠네요 ㅠㅠ
md5(uniqid(rand(), TRUE))를 사용하는 것보다 PHP 7에서는 bin2hex(random_bytes(32))이 보안상 안전하다고 해서 후자를 사용했네요.
(대략적으로 작성되어 아직 테스트된 바 없는 스크립트여서 오타와 수정할 부분이 많네요. 죄송합니다 ㅠㅠ)
<?php $sessdir = "경로"; // 세션 디렉토리를 별도로 관리해야 된다는 글을 읽었는데 정말 그런가요? ini_set('session.save_path', $sessdir); ini_set('session.cache_expire', 120); ini_set('session.gc_maxlifetime', 120); session_start(); $_SESSION['csrf_tokens'] = bin2hex(random_bytes(32)); // 토큰 생성 ?> <form name="login" method="post"> <input type="hidden" name="token" value="<?php echo $token $_SESSION['csrf_tokens'] ?>" /> </form> if (!empty($_POST['csrf_token'])) && (hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { unset($_SESSION['csrf_tokens']); // 토큰이 확인되면 세션 삭제 // 로그인 다음 과정 진행 } else { // 에러처리 } }
제가 보안에 대해 잘 몰라서 여쭤보는데요~ 이 스크립트에서 수정해야 할 부분이 어떤 것이 있을까요??
대략 위와 같은 방식으로 CSRF 토큰을 처리하고,
아울러 사이트 메인화면에 로그인 폼을 두지 않고, 로그인 버튼을 클릭하면 자바스크립트로 모달창이나 사이드바를 띄우는 방식을 사용하면
보안상 상대적으로 안전하고, 봇으로 광고글을 작성하는 것도 어느 정도 예방할 수 있을까요?
그런데 토큰을 정확히 어느 시점에 생성해야 되는지 제가 잘 모르겠네요 ㅠㅠ
로그인 버튼을 클릭할 때 생성하면 될까요?
만약 위 스크립트대로 한다면 로그인 버튼을 누르고 잠깐 다른 일을 보다가 120초가 경과하면 로그인을 못하게 되겠네요 ㄷㄷ
그럼 연말에 컨디션 관리 잘 하시고 뜻깊은 연말 보내세요 ^-^
저도 약속이 있어서 다시 나가볼게요~!
답변해주실 분께 미리 감사드립니다 :)
작성자
댓글 11
바쁘신데 답변해주셔서 감사합니다!
아직 적용해본 스크립트가 아니라서 대략적으로 작성하다보니 오타가 많아서 죄송하네요 ㅠㅠ
일단 제가 발견한 부분은 급히 수정했네요 ㅜㅜ
1. 스택오버플로우에 세션의 유효시간과 관련하여 다음과 같은 설명이 있어서 제가 디렉토리에 관한 질문을 드린 것이었어요 ^^
출처: https://stackoverflow.com/questions/520237/how-do-i-expire-a-php-session-after-30-minutes
// Change the save path. Sessions stored in the same path
// all share the same lifetime; the lowest lifetime will be
// used for all. Therefore, for this to work, the session
// must be stored in a directory where only sessions sharing
// it's lifetime are. Best to just dynamically create on.
2. 로그인 버튼을 클릭할 때 토큰을 생성하고, 로그인 모달창이 뜨면 입력을 받고 세션을 삭제하려고 하는데 이런 방식은 의미가 없을까요?
제가 세션을 최대한 짧게 잡고 폐기하려고 한 목적은 보안상 이유도 있고, 서버 부하의 측면도 있는데요.
제가 잘못 생각한 것일까요?? ㅠㅠ
로그인을 위한 CSRF 세션 토큰의 유효시간을 길게 잡는 것의 장점은 무엇인지 여쭤봅니다!
3. 말씀하신대로 그누보드는 write_token.php에서 토큰을 가져올 수 있고,
그런 방법이 아니더라도 작정하고 Selenium으로 도배하는 봇을 돌리면 막을 수 없긴 하죠 ㅜㅜ
저는 단지 그누보드 계열에서 범용으로 사용되는 도배봇이라도 막아보려고 하거든요.
그럼 Hanam09 님께서도 즐겁고 뜻깊은 연말 되세요~!
다시 한 번 감사드립니다 ^^
2번에 제가 "로그인 버튼을 누른다"라는것을 "로그인 폼을 제출한다"라고 잘못 해석한것으로 보입니다.
이니스프리님의 말씀처럼 로그인 모달을 생성할때 새션토큰을 생성하고 로그인값을 입력받으면 토큰만을 삭제하는것이 낳을듯 싶습니다.
유효기한 길게잡는건 대안입니다. 가장 이상적인 방법은, 토큰기한을 짧게 잡고 토큰이 죽을때마다 재발급요청을 하는게 좋다고 생각합니다.
앗 제가 부정확하게 질문을 드려서 혼동하신 것 같네요 ㅠㅠ
말씀하신대로 토큰 기한을 짧게 잡고 재발급하는 방식으로 하겠습니다.
다만 단순히 제가 생각한 방식으로 구현한다면
접속자가 로그인 버튼을 누르고 모달창이 뜬 상태에서 잠깐 다른 일을 보다가 토큰 기한을 경과하는 경우에는
사이트 로그인에 문제가 있다고 글이 종종 올라올 것 같네요 ㅎㅎ
아직 제가 PHP에서 세션과 쿠키를 간신히 적용하는 수준이어서 실제로 적용하려면 넘어야 할 어려운 문제가 많네요.
그럼 굿밤되세요~! 다시 한 번 감사드립니다 :)
1. 토큰을 저렇게 페이지에 직접적으로 박어버리는 경우에는 셀레늄을 이용하지 않더라도 csrf를 쉽게 우회할 수 있습니다.
네이버 같은 경우에는 bvsd 가 추가가 되면서 셀레늄을 이용하지 않으면 매우 귀찮도록 되어 있습니다.
즉 서버에서 받아온 값을 javascript로 암호화를 해서 hidden 값으로 동적으로 생성해서 전달하는 방식을 이용하고 있습니다.
2. 자바스크립트로 모달 창을 띄우거나 하는 것 만으로는 부족합니다. 아무리 모달창으로 띄운다고 해도 결국에는 폼으로 전송을 한다면 해당 전송 방식을 파이썬으로 흉내를 낼 수 있기 때문입니다.
정 브루트포싱이 걱정이 되신다면 해피머니나 아이핀과 같이 로그인을 할 때 캡챠를 입력을 받게 하는 방법이 있습니다.
바쁘신데 답변 달아주셔서 정말 감사합니다 ^^
humit 님의 말씀을 들으니 제가 보안을 너무 쉽게 생각했네요.
보안의 세계는 참 깊고 심오하군요 ㄷㄷ
제가 아직은 보안과 관련해서 그누보드를 수정할 실력이 안 되는 것 같네요.
일단 humit 님께서 말씀하신 bvsd에 대해 더 공부를 해볼게요~!
로그인할 때 캡챠를 입력받도록 하면 보안에는 확실히 도움이 되겠지만
정말 가치있는 컨텐츠가 있는 사이트가 아니라면 사이트를 문닫게 될 것 같네요 ㅠㅠ
그럼 humit 님께서도 굿밤되시고 즐거운 크리스마스 되세요~! :)
덕분에 여러모로 많이 배워서 항상 감사드립니다!!
참고로 bvsd가 기법이 아니라 네이버에서 저 이름로 된 hidden 타입의 input을 사용한다는 의미입니다.
앗 감사합니다 ^-^
말씀해주신 네이버를 개발자도구로 열어보니 nidlogin.login에서 bvsd란 폼을 전달하는군요~!
bvsd.1.3.4.min.js가 이와 관련된 것 같구요 ㄷㄷ
주말에 bvsd.1.3.4.min.js 이 파일을 꼼꼼하게 살펴볼게요 :)
제가 humit 님 말씀을 제대로 이해한 것인지는 모르겠지만
위에 있는 댓글에서 말씀해주신대로 폼으로 전송을 하는 방법을 택하지 않는다면,
HTML form 태그 대신에 자바스크립트의 prompt() 함수 등을 이용해서 로그인 모듈을 구현해서
id, pw와 함께 서버에서 받아온 값을 자바스크립트에서 암호화한 토큰값을 json 형식으로 보내고
이를 서버측(PHP)에서 file_get_contents으로 받는 방식을 택하면
폼을 사용하지 않으니 상대적으로 보안상 안전한 것인지 여쭤봅니다 ^^
그런데 이 댓글을 작성하다보니 이런 방식으로 로그인하도록 구현한 홈페이지가 많지 않다는 것이 떠오르면서
뭔가 지금 제가 잘못 생각하고 있다는 느낌이 드네요~! ^^;;;
그럼 humit 님께서도 즐거운 주말 보내세요 :)
항상 감사드립니다!!
네이버가 폼을 사용하긴 하지만 유사한 방법을 사용합니다.
로그인을 하면 자바스크립트로 id와 pw부분을 RSA 방식으로 암호화해서 해당 내용을 전달하고, id와 pw는 빈칸으로 보내는 방법을 채택하고 있습니다.
이렇게 하면 Wireshark와 같은 패킷 캡쳐 프로그램을 사용하더라도 아이디와 비밀번호 정보가 유출이 되지 않는다는 점이 있습니다.
물론 간단한 보안만 하신다면 로그인 부분에 https를 적용하시는 것만으로도 충분할 수 있습니다.
상세한 설명 감사합니다~!
말씀만 들어도 네이버의 경우에는 selenium을 사용하지 않고 로그인 하려면 상당히 골치아프겠군요 ㄷㄷ
SSL 이외에도 제 미천한 실력으로 적용 가능한 부분이 있으면 조금이라도 흉내를 내야겠네요 :)
스크립트에 오타가 많네요..
$token, crsf_token
----
안녕하세요.. 이니스프리님
Q.세션 디렉토리를 별도로 관리해야 된다는 글을 읽었는데 정말 그런가요?
A.딱히 세션토큰을 별도로 관리해야 하지는 않는다고 알고 있습니다.
Q.로그인 버튼을 클릭할 때 생성하면 될까요?
A.로그인 버튼을 클릭할때 세션토큰을 생성하는것은 의미가 없습니다...
세션토큰 유효시간을 길게 잡는것이 좋다고 생각합니다.
Q.보안상 상대적으로 안전하고, 봇으로 광고글을 작성하는 것도 어느 정도 예방할 수 있을까요?
A.어느정도 예방할 수 있겠지만 한계는 있습니다.
제가 어떤 대회가 있어서 게시글을 도배 수준으로(..)작성해야 할 때가 있었는데 그때 매번 해당 폼 입력 경로에서 AJAX로 세션 토큰을 매번 가져와서 개시글을 등록했었던때가 생각이 나네요.