리플레이 공격방식은 프레젠테이션 공격이라 부르는데, 정상적인 사용자가 인증권한을 취득하기 위해 전송한 데이터를 재전송하는 모든 종류의 공격을 말합니다.
리플레이 공격과 마찬가지로 패스워드 스니핑 공격을 차단하려는 노력은 많지만 완전하게 차단할 수 있는 방법은 없습니다.
그렇기 때문에 인증과정 중 폼의 여러 가지 속성을 설치한다 하더라도 공격자에게는 그다지 중요하지 않게 생각할 수 있으며 그래서인지 요즘은 HTTP요청내용과 HTTP응답내용이 노출되지 않게 보호하려고 SSL전송방식을 많이 이용하는 편입니다.
<form action=https://mydomain.com/login.php method="POST">
myid: <input type="text" name="username">
mypass: <input type="password" name="userpass">
</form>
개인이 호스팅을 임대받는 경우라면 SSL기능을 자유롭게 사용할 수 없으므로 get 전송방식보다는 인증노출이 적은 post 방식을 사용할 것을 권장하며, 비밀번호는 값을 MD5로 암호화하되 복잡한 암호를 사용하도록 사용자에게 유도하거나 개발자가 임의의 문자를 섞여 한번 더 암호화시켜 주어야 합니다.
다음으로 인증요청 무차별 공격 스크립트를 작성할 수 있습니다.
<form action="http://mydomain.com/login.php" method="POST"><br />
myid: <input type="text" name="username"><br />
mypass:<input type="password" name="userpass"><br />
</form>
<?php
$host = "mydomain.com";
$username = "habony";
$userpass = "1111";
$data = "username=$username&userpass=$userpass";
$len = strlen($data);
$request = '';
$request .= "POST /login.php HTTP/1.1\r\n";
$request .= "Host: ${host}\r\n";
$request .= "Content-Type: application/x-www-form-urlencoded\r\n";
$request .= "Content-Length: ${len}\r\n";
$request .= "Connection: close\r\n";
$request .= "\r\n";
$request .= "$data";
if($fp = fsockopen($host, 80)){
fputs($fp, $request);
$response = '';
while(!feof($fp)){
$response .= fgets($fp, 1024);
}
fclose($fp);
}
echo "$response<br />\n";
?>
이와 같은 작업으로 공격자는 인증시도를 하려할 것인데, $response의 결과에 따라 패스워드 취득 실패시 다른 패스워드 재시도 루틴을 요청할 수 있을 것입니다.
만약 사용자가 복잡한 암호를 구성하였다면, 공격자의 성공확률을 낮출 수 있습니다. 사용자 암호보호를 위해 암호화하는 것은 필요한 것이므로 무차별 공격을 어렵게 만들거나 성공확률을 낮추기 위해 30초정도 지연시킬 수 있습니다.
<?php
$uniqid = uniqid(rand());
$inputid = mysql_real_escape_string($_POST['inputid']);
있습니다.
$inputpass = md5($uniqid . "_habony_" . md5("habony_" .
$_POST['inputpass'], true));
$data = array();
$sql = array();
$now = time();
$login_conn = $now - 30;
if($sql = mysql_query("select logintime, inputpass from $db where
inputid='${inputid}'")){
if(mysql_num_rows($sql)){
$row = mysql_fetch_assoc($sql);
if($row['logintime'] > $login_conn){
exit("로그인 실패하여 30초가 지나야 로그인 가능합니다.");
} elseif($row['inputpass'] === $inputpass){
echo "로그인 인증되었습니다.";
} else {
mysql_query("update $db set logintime = '$now' where
inputid = '$inputid' ");
}
} else {
exit("해당하는 아이디가 없습니다.");
}
}
?>
파일업로드된 파일접근을 막기 위해 이것 역시 암호화하여 저장할 필요가 있습니다.
<?php
$uniqid = uniqid(rand());
$filename = base64_encode($_FILES['userfile']['name']);
$md5filename = md5($uniqid . "_habony_". md5_file($filename, true));
if($_FILES['userfile']['error'] === UPLOAD_ERR_OK) {
if($_FILES['userfile']['size'] <= 0){
echo "파일 업로드에 실패하였습니다.";
} else {
if(!is_uploaded_file($_FILES['userfile']['tmp_name'])) {
echo "HTTP로 전송된 파일이 아닙니다.";
} else {
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $md5filename)) {
echo "성공적으로 업로드 되었습니다.\n";
} else {
echo "파일 업로드 실패입니다.\n";
}
mysql_query("insert into $db values ('','$filename');
}
}
} else {
echo file_errmsg($_FILES['userfile']['error']);
}
?>