로그
에루라보
블로그 작업노트 29: 댓글 무차별 대입공격 방어 및 섬네일 추출 방식 변경
이번 긴 연휴 기간동안 블로그를 가끔가다 들어오게 되었는데, 약 2-30건의 무차별 댓글 대입 공격이 있었다는걸 눈치채게 되었다.
댓글 무차별 대입 공격 방어
서버에 남은 로그 기록을 바탕으로 체크해보니 역시 '그 나라' IP여서 아이피 대역 자체를 차단할까 싶었는데, 또 어찌될지 몰라서 일단은 아이피 블록 리스트를 만들어놔서 내가 지정한 아이피는 댓글을 못쓰게 막아두었다.
public static $denyIP = [
'000.000.000.000'
];
public static function isDeniedIP()
{
return in_array(Request::ip(), self::$denyIP);
}
Copy
위와같은 메소드를 Comment 모델에 구현해두고 댓글을 작성하는 메소드에 아래처럼 조건식을 하나 걸어주면 된다.
if (Comment::isDeniedIP()) {
return response('해당 IP에서는 댓글을 작성할 수 없습니다.', 403);
}
Copy
하지만 이래서는 일이 발생하고 나서 처리하는 방식에 불과했고, 백단에서 비정상적인 댓글 기록을 막기위한 추가 방책이 필요했다.
그래서 최근 5분이내에 3건이상의 댓글을 쓴 유저의 경우에는 일반적인 댓글의 작성시간을 고려해도 너무 빈번하다 생각이 되므로 그런 경우에는 예외처리를 할 수 있도록 기능을 추가해보았다.
위의 Comment 모델에 추가한 메소드처럼 아래 메소드를 추가해주었다.
public static function isTooFrequent(string $ip, int $threshold = 3, int $minutes = 5): bool
{
return self::where('ip_address', $ip)
->where('created_at', '>=', now()->subMinutes($minutes))
->count() >= $threshold;
}
Copy
그리고 위 메소드를 실행시키는 구문을 댓글 추가 기능에 더하면된다.
public function addComment(Request $request, $id)
{
if (Comment::isDeniedIP()) {
return response('해당 IP에서는 댓글을 작성할 수 없습니다.', 403);
}
if (Comment::isTooFrequent($request->ip())) {
return response('너무 잦은 댓글 등록으로 인해 잠시 후 다시 시도해주세요.', 429);
}
....
Copy
이러면 쉽게 백단에서 IP 기반으로 빈도가 높은 작업에 대한 예외처리를 실행할 수 있다.
위 작업을 하면서 기존에 에러메시지가 영어로뜨던 부분도 전부 한글로 보일 수 있게 보정작업을 했고, 현재 테스트해본바 정상적으로 예외처리가 작동된다는걸 확인했다.
섬네일 추출 방식 변경
기존에 나는 정규식을 통해서 특정 class 명을 가지고있는 줄을 추출해 그 줄의 src 주소를 가져오는 방식의 코드로 섬네일을 추출했다.
// `class="og_image"`가 포함된 이미지는 제외하고, `https://cdn.erulabo.com`로 시작하는 이미지 src만 추출
preg_match("/<img(?:(?!class=\"og_image\").)*?src=[\"'](https:\/\/cdn\.erulabo\.com[^\"]+)[\"'][^>]*>/i", $post->body, $images);
$post->image = $images[1] ?? null; // 매칭된 이미지 URL이 없으면 null
Copy
근데 이렇게 하니까 좀 문제가 발생했는데, 클래스에 og_image와 더불어 fr-dib, fr-div 이런 클래스명이 더해진다면 해당 정규식에 걸러지지 않는다는것이었다.
간단히 만들 수 있을줄 알았는데, 생각보다 0...* 처리가 정규식상에선 힘들다고 한다.
그래서 해당 기능을 좀 무겁지만 DOM 파서 기능을 통해 아래와 같이 재구현해보았다.
public function extractMainImage(): void
{
if (!$this->body) {
$this->image = null;
return;
}
$dom = new \DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML('<?xml encoding="UTF-8">' . $this->body);
libxml_clear_errors();
$imgs = $dom->getElementsByTagName('img');
foreach ($imgs as $img) {
$src = $img->getAttribute('src');
$class = $img->getAttribute('class');
if (!str_contains($class, 'og_image')) {
$this->image = $src;
return;
}
}
$this->image = null;
}
Copy
재사용이 가능하게 모델 메소드로 따로 빼서 구현해보았다.
그리고 위 코드를 아래와 같이 이용하면 끝이다.
if ($request->input('use_image')) {
$post->extractMainImage();
} else {
$post->image = null;
}
Copy
그래서 실제 글의 섬네일을보면,

이런식으로 보여지는데, 글의 내부를보면 섬네일에 사용된 이미지보다 상위에,

오픈그래프 링크의 이미지가 있다.
하지만 위 코드의 목적에 맞게 og_image 클래스를 가지고있는 img는 무시하고 아래의 img의 src가 추출됨을 확인할 수 있다.
이로써 가끔가다 이상하게 섬네일이 잡혔던 문제를 해결했다.
#문제해결 #블로그
0
개의 댓글
에루라보 콜렉션의 다른 글
로그 카테고리의 다른 글

05/05
28주차 그림결산
28주차 그림은 두장을 그려봤다. 첫번째 그림은 바니걸 복장을한 레라를 그려보았다.뭔가 역동적인 자세를 취한 모습을 그려보고 싶어서 그려봤는데 나름 구도가 마음에 들어서 재미있게 그렸던 그림이다. 뭔가 머리 부분을 좀 잘 그려보고 싶어서 라인색을 머리카락과 같게 바꿔보고 피부쪽의 라인도 바꿔봤는데 확실히 이...

04/29
자동차 구경하러 킨텍스 다녀온 썰, 2025 서울모빌리티쇼
다녀온지는 한참되긴했는데, 걍 겸사겸사 사진정리도 좀 할겸 방문기를 써보려한다.때는 4월초, 친구랑 일산에서 놀게되다가 우연히 해당일에 킨텍스에서 모빌리티쇼를 한다는걸 알게되었다. 매년 진행하는 행사로 이번엔 킨텍스에서 한다길래 바로 당일날 호다닥 가보게되었다.근데 재수가 없는건지 있는건지(이는 나중에...

04/28
27주차 그림결산
이번주는 독감같은 감기에 걸려서 일주일 동안 아주 고생을 했다.보통 아침에 일찍 출근에서 차에서 그리곤 하는데, 이번주는 피곤해서 그냥 차에서 졸다가 나오는 경우도 태반이었고, 점심에도 밀폐된 공간에 있으면 안될거같아서 좀 나돌아 다니는거 때문에 주중에 그림을 잡고있질 못했다. 그래서 이번주는 그냥 적당히...