비밀번호를 안전하게 저장하고 두 번째 수단을 더해도, 로그인 문 앞에서 끊임없이 시도를 던지는 공격은 남는다. 자동화된 프로그램이 수많은 비밀번호 후보나 어딘가에서 새어 나온 계정 정보를 대량으로 밀어 넣어 문이 열리기를 노리는 것이다. 이런 시도는 사람의 손이 아니라 기계의 반복으로 이루어지므로, 방어도 개별 시도가 아니라 그 대량성과 자동성을 겨냥해야 한다.
이번 편은 대량의 시도로 계정을 노리는 공격이 어떤 형태를 띠는지, 시도의 빈도를 제한하는 방어가 어떻게 작동하는지, 잠금과 지연을 어떻게 다루는지, 사람과 기계를 구별하는 확인이 어떤 자리에 놓이는지, 이미 새어 나간 정보에 어떻게 대비하는지, 그리고 이상 징후를 어떻게 살피는지를 다룬다. 공격의 수법을 아는 것은 오직 그 길목을 막기 위해서다.
대량 시도가 노리는 것
로그인 문을 노리는 대량 시도에는 크게 두 갈래가 있다. 하나는 한 계정을 정해 두고 수많은 비밀번호 후보를 차례로 던지는 것이고, 다른 하나는 어딘가에서 새어 나온 계정과 비밀번호의 짝을 여러 서비스에 그대로 밀어 넣는 것이다. 앞의 것은 비밀번호를 맞히려는 시도이고, 뒤의 것은 이미 새어 나온 짝이 이 서비스에서도 통하는지 확인하는 시도다.
후보를 던지는 시도는 비밀번호가 약할수록 잘 통한다. 짧거나 흔한 비밀번호는 후보 목록의 앞쪽에 있어 금세 맞으므로, 이런 비밀번호를 쓴 계정이 먼저 뚫린다. 그래서 이 시도에 대한 방어는 비밀번호의 질을 높이는 방어와, 시도의 빈도를 제한하는 방어가 함께 작동해야 힘을 낸다.
새어 나온 짝을 밀어 넣는 시도는 사람들이 여러 서비스에 같은 비밀번호를 쓰는 습관을 파고든다. 한 서비스에서 새어 나온 짝이 다른 서비스에서도 그대로 통하는 경우가 많기 때문이다. 이 시도는 비밀번호를 맞히는 것이 아니라 이미 아는 짝을 대량으로 시험하는 것이라, 비밀번호가 강해도 재사용되었다면 통한다.
두 시도 모두 자동화된 반복에 기댄다는 공통점이 있다. 사람이 하나하나 입력하는 것이 아니라 프로그램이 짧은 시간에 수많은 시도를 던진다. 그래서 방어의 핵심은 이 대량의 자동 시도를 어렵게 만드는 데 있다. 시도 하나하나를 막기보다, 대량으로 반복하는 것 자체를 감당하기 어렵게 하는 것이다.
시도의 빈도를 제한하기
가장 기본적인 방어는 짧은 시간에 던질 수 있는 시도의 수를 제한하는 것이다. 같은 출처나 같은 계정을 향한 로그인 시도가 정해진 횟수를 넘으면, 그 뒤의 시도를 잠시 거부하거나 늦춘다. 대량 시도는 빠른 반복에 기대므로, 반복의 속도를 늦추는 것만으로도 공격의 효율이 크게 떨어진다.
제한의 기준은 여러 각도로 둘 수 있다. 한 계정을 향한 시도를 세어 그 계정을 노리는 집중 공격을 막고, 한 출처에서 오는 시도를 세어 여러 계정을 훑는 공격을 막는다. 어느 한 기준만으로는 다른 각도의 공격이 빠져나가므로, 계정 단위와 출처 단위를 함께 보는 것이 촘촘하다.
다만 출처를 기준으로 삼을 때는 여러 사용자가 같은 출처로 묶여 보일 수 있음을 고려해야 한다. 여러 사람이 하나의 통로를 거쳐 나오는 경우, 그 출처를 통째로 막으면 무고한 사용자까지 막힌다. 그래서 출처 단위 제한은 계정 단위 제한과 함께 쓰되, 정당한 사용자가 휩쓸리지 않도록 그 폭을 신중히 정한다.
빈도 제한은 정당한 사용자에게는 거의 영향을 주지 않아야 한다. 사람은 짧은 시간에 수십 번씩 로그인을 시도하지 않으므로, 정상적인 사용을 넉넉히 감싸는 선에서 제한을 두면 정당한 사용자는 그 벽에 닿지 않는다. 반면 대량으로 반복하는 시도는 그 벽에 곧 걸린다. 정상에는 가볍고 공격에는 무거운 이 비대칭이 빈도 제한의 핵심이다.
잠금과 지연을 다루기
시도가 일정 횟수를 넘었을 때의 대응으로는 잠금과 지연이 있다. 잠금은 그 계정이나 출처의 시도를 한동안 아예 막는 것이고, 지연은 시도를 거부하지는 않되 응답을 점점 늦추는 것이다. 둘은 각각 장단이 있어, 상황에 맞게 고르거나 함께 쓴다.
계정을 잠그는 방어에는 조심할 점이 있다. 한 계정을 향한 시도가 많다고 그 계정을 잠그면, 공격자가 일부러 남의 계정에 틀린 시도를 던져 그 계정을 잠기게 만드는 방해가 가능해진다. 방어가 오히려 정당한 사용자를 가두는 수단으로 악용되는 것이다. 그래서 계정 잠금은 신중히 쓰고, 잠금 대신 지연이나 추가 확인으로 무르게 다루는 방식도 함께 고려한다.
지연은 이 방해의 위험이 적다. 시도가 늘어날수록 응답을 조금씩 늦추면, 대량 시도는 반복이 느려져 감당하기 어려워지는 반면 정당한 사용자는 어쩌다 한두 번 틀려도 큰 불편을 겪지 않는다. 시도를 완전히 막지 않으면서도 대량 반복만 무겁게 만드는 절충이다.
잠금을 쓸 때는 풀리는 길을 함께 마련해야 한다. 시간이 지나면 자동으로 풀리게 하거나, 다른 확인 수단으로 정당한 사용자가 잠금을 풀 수 있게 한다. 잠금이 영구적이면 방해에 그대로 악용되고 정당한 사용자도 갇히므로, 잠금은 일시적이고 풀 수 있는 것이어야 한다. 방어가 사용자를 가두는 함정이 되지 않게 하는 것이다.
사람과 기계를 구별하기
대량 시도는 자동화된 프로그램이 일으키므로, 요청을 보낸 것이 사람인지 기계인지를 구별할 수 있으면 방어에 큰 도움이 된다. 사람은 쉽게 통과하지만 기계는 통과하기 어려운 확인을 로그인 앞에 두어, 자동화된 반복을 걸러 내는 것이다. 이 확인은 대량성과 자동성을 정면으로 겨냥한다.
이 확인을 매 로그인마다 요구하면 정당한 사용자에게 번거로우므로, 위험이 높아 보일 때만 요구하는 방식이 흔히 쓰인다. 시도가 잦거나 낯선 출처에서 올 때처럼 의심스러운 신호가 있을 때 이 확인을 더하고, 평범한 로그인에서는 요구하지 않는다. 위험의 정도에 따라 확인을 조절해 부담과 방어의 균형을 잡는 것이다.
이런 확인은 완벽한 방어라기보다 공격의 비용을 높이는 장치로 이해하는 것이 맞다. 자동화를 어렵게 만들어 대량 시도의 효율을 떨어뜨리는 것이 목적이지, 모든 자동 시도를 남김없이 막는 것은 아니다. 그래서 이 확인은 빈도 제한이나 지연 같은 다른 방어와 함께 쓰여, 겹겹의 벽 가운데 한 겹으로 작동한다.
이 확인이 정당한 사용자에게 지나친 장벽이 되지 않도록 하는 것도 중요하다. 확인이 너무 어렵거나 자주 요구되면, 방어가 오히려 사용자를 밀어낸다. 그래서 사람에게는 부담이 작고 기계에는 통과가 어려운 확인을 고르고, 요구하는 시점도 위험이 높은 순간으로 좁힌다. 방어와 사용성의 균형이 여기서도 관건이다.
이미 새어 나간 정보에 대비하기
새어 나온 짝을 밀어 넣는 시도에는, 이미 새어 나간 것으로 알려진 비밀번호를 거르는 방어가 특히 유효하다. 다른 곳에서 새어 나가 널리 알려진 비밀번호는 이 서비스에서 처음 쓰더라도 위험하므로, 가입이나 변경 시점에 그런 비밀번호를 걸러 처음부터 쓰지 못하게 한다. 새어 나간 짝이 이 서비스에서 통할 여지를 줄이는 것이다.
비밀번호 재사용을 줄이도록 이끄는 것도 이 방어의 연장이다. 사용자가 여러 서비스에 같은 비밀번호를 쓰지 않게 하면, 한 곳에서 새어 나가도 다른 곳이 함께 뚫리지 않는다. 두 번째 인증 수단을 권하는 것도 같은 맥락이다. 비밀번호가 새어 나가 밀어 넣어져도, 두 번째 수단이 있으면 그 하나만으로는 문이 열리지 않는다.
새어 나온 짝을 시험하는 시도는 대개 성공률이 낮아도 대량으로 이루어진다. 수많은 짝 가운데 일부만 통해도 이득이므로, 넓게 훑는 것이다. 그래서 이 시도에 대한 방어도 개별 시도를 막기보다 대량의 훑기를 어렵게 만드는 데 초점을 둔다. 빈도 제한과 사람 확인이 여기서도 함께 작동한다.
이 서비스의 정보가 새어 나갔을 가능성에도 대비해야 한다. 저장소가 새어 나가더라도 비밀번호가 그대로 드러나지 않도록 안전하게 저장하는 것이 그 대비의 바탕이다. 새어 나간 정보에 대비한다는 것은 남이 새어 나간 것을 막는 일과, 우리가 새어 나가더라도 피해를 줄이는 일을 함께 포함한다.
이상 징후를 살피기
대량 시도는 평소와 다른 흔적을 남긴다. 특정 계정이나 출처에서 실패한 로그인이 갑자기 몰리거나, 낯선 곳에서의 시도가 늘거나, 짧은 시간에 여러 계정을 훑는 양상이 나타난다. 이런 흔적을 살피면 공격이 진행 중임을 알아채고 대응할 수 있다.
그래서 로그인 시도의 성공과 실패를 기록해 두는 것이 방어의 바탕이 된다. 실패가 몰리는 계정, 시도가 잦은 출처, 낯선 위치에서의 접근 같은 신호를 기록에서 읽어 내면, 어디를 더 조여야 하는지가 드러난다. 기록이 없으면 공격이 지나간 뒤에도 무슨 일이 있었는지 알 수 없다.
이상 징후가 감지되면 방어를 그 순간에 맞게 높인다. 평소에는 요구하지 않던 사람 확인을 더하거나, 빈도 제한을 조이거나, 의심스러운 계정에 두 번째 수단을 요구하는 식이다. 위험이 낮을 때는 부담을 덜고 위험이 높아지면 조이는 이 조절이, 사용성과 방어를 함께 지키는 길이다.
기록을 남길 때는 그 기록에 민감한 값이 그대로 담기지 않도록 주의해야 한다. 시도의 흔적을 남기되 비밀번호 같은 값은 기록에 두지 않고, 기록 자체도 보호한다. 방어를 위한 기록이 새어 나가 오히려 위험이 되지 않도록, 무엇을 남기고 무엇을 남기지 않을지를 신중히 정한다.
방어를 겹치고 균형을 잡기
지금까지의 방어들은 어느 하나만으로 대량 시도를 온전히 막지 못한다. 빈도 제한은 출처를 바꿔 오는 시도에 약하고, 사람 확인은 우회될 수 있으며, 새어 나간 비밀번호 거르기는 아직 알려지지 않은 짝을 막지 못한다. 그래서 이 방어들을 겹쳐 서로의 빈틈을 메운다.
빈도 제한과 지연으로 대량 반복을 무겁게 하고, 사람 확인으로 자동화를 어렵게 하며, 새어 나간 비밀번호를 걸러 이미 아는 짝이 통하지 않게 하고, 두 번째 수단으로 비밀번호 하나가 뚫려도 문이 열리지 않게 한다. 여기에 이상 징후를 살펴 위험이 높아지면 방어를 조인다. 이 겹침이 어느 한 방어의 빈틈을 다른 방어가 메우는 체계를 이룬다.
겹치되 정당한 사용자의 부담을 잊지 말아야 한다. 방어를 두껍게 하려다 로그인이 지나치게 번거로워지면, 사용자가 떠나거나 더 약한 방식으로 우회하려 든다. 그래서 방어는 위험이 낮은 평상시에는 가볍게 두고 위험이 높아질 때 조이는 방향으로 설계한다. 늘 최대로 조이기보다 상황에 맞게 조절하는 것이 지속 가능한 방어다.
이 방어들은 인증의 다른 부분과 맞물려야 제 값을 한다. 비밀번호의 안전한 저장, 두 번째 수단, 세션의 적절한 관리가 함께 튼튼할 때, 문 앞의 대량 시도를 막는 방어도 온전한 체계의 한 부분으로 작동한다. 어느 한 방어가 홀로 서는 것이 아니라, 여러 방어가 맞물려 하나의 문을 지키는 것이다.
정리하면 대량 시도는 후보를 던지거나 새어 나온 짝을 밀어 넣는 자동화된 반복이며, 방어는 시도의 빈도를 제한하고, 잠금과 지연을 신중히 다루고, 사람과 기계를 구별하고, 새어 나간 정보에 대비하고, 이상 징후를 살피는 것으로 이루어진다. 어느 하나로는 부족하므로 이 방어들을 겹치되, 정당한 사용자의 부담을 줄이도록 위험에 따라 조절해야 한다. 방어의 초점은 시도 하나하나를 막는 데 있지 않고 대량으로 반복하는 것 자체를 감당하기 어렵게 만드는 데 있음을 잊지 말아야 한다. 다음 편에서는 인증에 쓰이는 값들을 안전하게 저장하고 전송하는 방법을 들여다본다.