제퍼넷 로고

비하인드 스토리: 사용자 입력을 절대 신뢰하지 마세요

시간

이 기사는 지난 8년 동안 다양한 SaaS 제품과 웹사이트를 운영하는 방법에 관해 제가 쓰고 있는 일련의 게시물 중 첫 번째입니다. 저는 제가 다루었던 몇 가지 문제, 제가 배운 교훈, 제가 저지른 실수, 그리고 아마도 제대로 된 몇 가지 사항을 공유할 것입니다. 나 한테 알려줘 당신의 생각!

2019년이나 2020년에 저는 전체 백엔드를 다시 작성하기로 결정했습니다. 발신자 차단, 사용자가 다른 기능 중에서 더 나은 이메일 블록을 생성하는 데 도움이 되는 SaaS 애플리케이션입니다. 그 과정에서 몇 가지 새로운 기능을 추가하고 훨씬 더 현대적인 기술로 업그레이드했습니다. 테스트를 실행하고, 코드를 배포하고, 프로덕션의 모든 것을 수동으로 테스트했는데, 몇 가지 무작위 확률을 제외하면 모든 것이 잘 작동하는 것 같았습니다. 이걸로 이야기가 끝났으면 좋겠지만…

몇 주 후, 한 고객으로부터 서비스가 작동하지 않고 받은편지함에 차단되어야 할 이메일이 너무 많이 수신되고 있다는 통보를 받았습니다(그 자체로 당혹스럽습니다). 그래서 조사했습니다. 이 문제는 Google이 서비스에서 사용자 계정으로의 연결을 제거했기 때문에 발생하는 경우가 많습니다. 시스템에서는 이메일을 통해 사용자에게 알리고 다시 연결하도록 요청하여 처리하지만 이번에는 다른 문제였습니다.

사용자 차단에 대한 이메일 확인을 처리하는 백엔드 작업자가 5~10분마다 계속 충돌하는 것처럼 보였습니다. 가장 이상한 부분은 로그에 오류가 없었고 메모리도 괜찮았지만 CPU가 가끔 무작위로 급증하는 경우가 있다는 것입니다. 그래서 다음 24시간 동안(잠자기 위한 3시간 휴식 – 고객 여러분 죄송합니다 😬) 충돌이 발생할 때마다 작업자를 수동으로 다시 시작해야 했습니다. 어떤 이유로 Elastic Beanstalk 서비스가 다시 시작하는 데 너무 오랜 시간이 걸렸기 때문에 수동으로 다시 시작해야 했습니다.

프로덕션에서 문제를 디버깅하는 것은 항상 고통스러운 일입니다. 특히 문제의 원인을 파악하는 것은 고사하고 문제를 로컬에서 재현할 수도 없기 때문에 더욱 그렇습니다. 그래서 다른 "훌륭한" 개발자처럼 저도 방금 로깅을 시작했습니다. 모두 서버가 다시 충돌할 때까지 기다렸습니다. CPU가 주기적으로 급증했기 때문에 매크로 문제(예: 메모리 부족 등)가 아니며 특정 이메일이나 사용자로 인해 발생한 것일 수 있다고 생각했습니다. 그래서 범위를 좁혀 보았습니다.

  • 특정 이메일 ID나 유형에서 충돌이 발생했나요?
  • 특정 고객에 대해 충돌이 발생했습니까?
  • 일정한 간격으로 충돌이 발생했습니까?

몇 시간 동안 생각했던 것보다 오랫동안 로그를 살펴본 끝에 결국 특정 고객으로 범위를 좁혔습니다. 거기에서 검색 공간이 상당히 좁아졌습니다. 이는 차단 규칙이거나 서버가 계속 재시도하는 특정 이메일일 가능성이 높습니다. 운 좋게도 전자였습니다. 우리는 개인 정보 보호에 중점을 두고 어떤 이메일 데이터도 저장하거나 조회하지 않는다는 점을 고려하면 디버깅하기가 훨씬 쉬운 문제였습니다.

정확한 문제에 들어가기 전에 먼저 Block Sender의 기능 중 하나에 대해 이야기하겠습니다. 당시에는 동일한 패턴을 따르는 특정 유형의 이메일 주소를 차단할 수 있는 와일드카드 차단을 요청하는 고객이 많았습니다. 예를 들어 마케팅 이메일 주소의 모든 이메일을 차단하려면 와일드카드를 사용할 수 있습니다. marketing@* 다음으로 시작하는 모든 주소에서 오는 모든 이메일을 차단합니다. marketing@.

제가 생각하지 못한 한 가지는 모든 사람이 와일드카드의 작동 방식을 이해하지 못한다는 것입니다. 나는 대부분의 사람들이 내가 개발자로서 하는 것과 같은 방식으로 그것들을 사용할 것이라고 생각했습니다. * 원하는 수의 문자를 나타냅니다. 불행하게도 이 특정 사용자는 귀하가 다음을 사용해야 한다고 가정했습니다. 일치시키려는 각 문자에 대해 하나의 와일드카드. 그들의 경우, 그들은 특정 도메인에서 오는 모든 이메일을 차단하기를 원했습니다(이는 Block Sender의 기본 기능이지만 이를 깨닫지 못했음에 틀림없으며 이는 그 자체로 전체적인 문제입니다). 그래서 사용하는 대신 *@example.com, 그들은 사용했다 **********@example.com.

POV: 사용자가 앱을 사용하는 것을 지켜보는 중...
POV: 사용자가 앱을 사용하는 것을 지켜보는 중...

작업자 서버에서 와일드카드를 처리하기 위해 Node.js 라이브러리를 사용하고 있습니다. 매처, 정규식으로 변환하여 전역 일치에 도움이 됩니다. 그러면 이 라이브러리는 **********@example.com 다음 정규식과 같은 것으로 바꾸십시오.

/[sS]*[sS]*[sS]*[sS]*[sS]*[sS]*[sS]*[sS]*[sS]*[sS]*@example.com/i

정규식에 대한 경험이 있다면 특히 계산 수준에서 매우 빠르게 매우 복잡해질 수 있다는 것을 알고 있습니다. 위의 표현식을 적당한 길이의 텍스트와 일치시키는 것은 계산 비용이 매우 많이 들고, 결국 작업자 서버의 CPU를 묶게 됩니다. 이것이 서버가 몇 분마다 충돌하는 이유입니다. 복잡한 정규 표현식을 이메일 주소와 일치시키려고 하면 중단될 수 있습니다.. 따라서 이 사용자가 이메일을 받을 때마다 일시적인 오류를 처리하기 위해 내장된 모든 재시도 외에도 서버가 중단됩니다.

그럼 이 문제를 어떻게 고쳤나요? 분명히 빠른 수정은 여러 와일드카드가 연속적으로 포함된 모든 블록을 찾아서 수정하는 것이었습니다. 하지만 사용자 입력을 더 잘 정리하는 작업도 필요했습니다. 모든 사용자는 정규식을 입력하고 다음과 같이 전체 시스템을 중단할 수 있습니다. ReDoS 공격.

모범 사례, 업계에서 인정하는 표준 및 포함된 치트 시트가 포함된 Git 학습에 대한 실습 가이드를 확인하십시오. 인터넷 검색 Git 명령을 중지하고 실제로 배움 이것!

이 특정 사례를 처리하는 것은 매우 간단했습니다. 연속된 와일드카드 문자를 제거하면 됩니다.

block = block.replace(/*+/g, '*')

하지만 여전히 앱은 다른 유형의 ReDoS 공격에 노출되어 있습니다. 운 좋게도 이러한 유형에도 도움이 되는 여러 패키지/라이브러리가 있습니다.

위의 솔루션과 기타 보호 조치를 함께 사용하여 이러한 일이 다시 발생하는 것을 방지할 수 있었습니다. 하지만 이는 사용자 입력을 절대 신뢰할 수 없으며 애플리케이션에서 사용하기 전에 항상 이를 삭제해야 한다는 점을 상기시켜 주는 좋은 내용이었습니다. 나는 이것이 나에게 일어날 때까지 이것이 잠재적인 문제라는 것을 몰랐습니다. 따라서 이것이 다른 사람이 같은 문제를 피하는 데 도움이 되기를 바랍니다.

질문이나 의견이 있거나 자신의 이야기를 공유하고 싶으십니까? 연락하세요 트위터!

spot_img

최신 인텔리전스

spot_img