여러 로그인 로직의 우회 기법 연구는 피곤한 관계로 이번주 내로 올릴 것이다.
우선 기본적인 형태이다.
//check_login.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<?php
session_start();
$host = 'localhost';
$user = 'conn';
$pw = 'Testnote!%89';
$db_name = 'test';
$mysqli = new mysqli($host, $user, $pw, $db_name);
$username = $_POST['id'];
$userpass = $_POST['pw'];
$q = "SELECT * FROM member WHERE id = '$username' AND pw = '$userpass'"
$result = $mysqli->query($q);
$row = $result->fetch_array(MYSQLI_ASSOC);
if($row != null){
$_SESSION['username'] = $row['id'];
$_SESSION['name'] = $row['name'];
echo "<script>location.replace('index.php');</script>";
exit;
}
if($row == null){
echo "<script>alert('Invalid username or password')</script>";
echo "<script>location.replace('login.php')</script>";
exit;
}
?>
</body>
</html>
//check_login3.php
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<?php
session_start();
$host = 'localhost';
$user = 'conn';
$pw = 'Testnote!%89';
$db_name = 'test';
$mysqli = new mysqli($host, $user, $pw, $db_name);
$username = $_POST['id'];
$userpass = $_POST['pw'];
$q = "SELECT pw FROM member where id = '$username'"
$result = $mysqli->query($q);
$row = $result->fetch_array(MYSQLI_ASSOC);
if($row['pw'] == $userpass){
$_SESSION['username'] = $row['id'];
$_SESSION['name'] = $row['name'];
echo "<script>location.replace('index.php');</script>";
exit;
}
else{
echo "<script>alert('Invalid username or password')</script>";
echo "<script>location.replace('login.php')</script>";
exit;
}
?>
</body>
</html>
아래부터는 위의 두 방식의 여러가지 표현법이다. 여러 방법이 있겠지만, 대표적인 방법만 설명해보겠다.
$q = "SELECT * FROM member WHERE (id = '$username' AND pw = '$userpass')"
$result = $mysqli->query($q);
$row = $result->fetch_array(MYSQLI_ASSOC);
Where 이후로 괄호를 씌워 만약 주석(#)이 들어오게 되면 ')'가 생략이 되어 오류를 일으키게 된다. 이를 이용해 SQL Injection을 막는 방법이 있다.
$q = "SELECT * FROM member WHERE id = '$username' AND pw = '$userpass'";
$q1 = str_replace('#', '', $q);
$result = $mysqli->query($q);
$row = $result->fetch_array(MYSQLI_ASSOC);
특정 문자가 들어오게 된다면 그 문자를 생략해주는 str_replace함수를 사용한다. 이 경우에는 주석(#)이 들어오는 경우 #을 없애서 생략하고자 했던 부분을 활성화시켜 오류를 일으키게 된다. 이를 이용해 SQL Injection을 막는다.
$q = "SELECT uid
FROM member m1
JOIN member m2 ON m2.pw = '$userpass' AND m1.uid = m2.uid
WHERE m1.id = '$username'"
$result = $mysqli->query($q);
$row = $result->fetch_array(MYSQLI_ASSOC);
아쉽게도 MySQL에는 intersect(합집합)에 대한 내용이 없다. 그래서 (inner) Join으로 교집합을 만들어보았다. 복잡해서 이렇게 하면 제대로 인증이 되는지 모르겠다.
$q1 = "SELECT pw FROM member where id = '$username'"
$q = replace(' union ', '', strtolower($q1));
$result = $mysqli->query($q);
$row = $result->fetch_array(MYSQLI_ASSOC);
식별&인증_2에서와 마찬가지로 union이라는 문자가 있다면 생략되도록 만들었다. 그리고 대문자를 이용해 공격에 성공할 수도 있기 때문에 소문자로 만들어주는 strtolower함수를 사용했다.