SQL Injection Attacks - Ver. 1 By Spirito (admin@spirito.co.kr) SQL Injection Attack이무엇인지알아봅시다. 우선, 우리가이용하고있는웹사이트에는거대한저장공간이따로있습니다. 이공간에는, 사용자 ID, 사용자패스워드, 주소, 취미, 핸드폰등의여러가지들이들어있습니다. 우선네OO에블로그나, 카페에글을작성하려면로그인을해야되죠? [ 로그인 ] -> [SQL SERVER] -> [ 승인 / 비승인 ] 이렇게크게 3 부분으로볼수있겠는데요. 로그인을하게되면 SQL SERVER 로가서해당 Id 와 Password 가있는지없는지확인후 없거나, 있는데 Password 가틀린다면로그인이안되겠죠? 만약에있다면패스워드를확인후맞는다면바로로그인이되겠고요. 여기 Id, Password 의 data 들은 store 에저장이됩니다. 이것들이모이고모이면 바로 database 가되고요. 지금제일중요한부분은 Client( 유저 ) à Server( 회사 ) à Client( 유저 ) 입니다. 즉, Server 를거쳐서간다는것인데요. Server 를거친다는것은악용이가능하다는것이고, 악용한다는것은어떠한정보를빼 내거나, 이용을당하거나여러가지가있다는것을의미합니다. 그렇다면, 우리가지금부터알아야할 SQL Injection 을살펴보도록하겠습니다.
C# - SQL Injection Vulnerability Code Main.aspx <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="SQL_INJECTION._Default" %> <!-- Authoed by SPIRITO (admin@spirito.co.kr)--> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title> 해커스쿨로그인페이지 </title> </head> <body> <form id="form1" action="login.aspx" runat="server" > <div> ID : <input name="userid" type="text" /> PW : <input name="passwd" type="text" /> <input type="submit" name="btnsend" value=" 로그인 " /> <br /> <asp:label ID="lblOut" runat="server"></asp:label> </div> </form> </body> </html> 우선 Id 와 Password 를입력할수있는페이지를만들어두면, 우리는 id 와 password 를웹페이지를통해입력이가능하게됩니다.
login.aspx.cs // Authored by SPIRITO (admin@spirito.co.kr) // www.spirito.co.kr / www.hacekrschool.org namespace SQL_INJECTION public partial class login : System.Web.UI.Page protected void Page_Load(object sender, EventArgs e) try // Authored By Spirito (admin@spirito.co.kr) // SQL Injection Vulnerability in ASP.NET 3.5 string userid = Request["userID"]; string passwd = Request["passWD"]; Response.Write("ID : " + userid + "<br />" + "PW : " + passwd + "<br />"); string connstr = "address=ipaddress;user Id=spirito;password=XXXXXXX;database=XXXXXXX"; string sqlquery = "select id, pwd from wiseguyz where id='" + userid + "' and pwd ='" + passwd + "'"; // Sql Connection SqlConnection sqlconn = new SqlConnection(connStr); sqlconn.open(); // Sql Command SqlCommand sqlcomm = new SqlCommand(); sqlcomm.commandtext = sqlquery; sqlcomm.commandtimeout = 10; sqlcomm.commandtype = CommandType.Text; sqlcomm.connection = sqlconn;
Response.Write(sqlQuery); // ExceuteScalar가실행되어정상적이면그뒤에코드가작동됨 // 비번이맞지않으면바로에러를뿜는다. object sqlresult = sqlcomm.executescalar(); SqlDataReader sqlread = sqlcomm.executereader(); if ( sqlresult.tostring()!= null ) Response.Write("<br /> ExceuteScalar : " + sqlresult.tostring() + "<br />"); //for (int i = 0; i < sqlread.fieldcount; i++) //Response.Write("<br />" + sqlread.getname(i) + "<br />"); while (sqlread.read()) for (int i = 0; i < sqlread.fieldcount; i++) Response.Write(sqlRead[i] + " "); sqlread.close(); sqlconn.close(); catch (Exception ex) Response.Write("<br /> <font color=red> 접근권한이없습니다.</font>");
위의예제는 SQL Injection 에취약한데요. 왜그런지지금부터알아보도록하겠습니다. 먼저 Main.aspx 의소스에서 action=login.aspx, 그리고텍스트박스가보입니다. 여기서유추해보면이폼에있는값들이 login.aspx 로전달된다는것을예상을해볼수 도있는데요. 문제는어떤값들이어떻게넘어가는지모르는상태인데, name= userid, name="passwd" 이두가지의텍스트 id 들이, login.aspx 으로넘어가서 SQL Server 로전달된다는것을크게이해하시면될듯합니다. 위의예제를보면, string userid = Request["userID"]; string passwd = Request["passWD"]; 위와같은코드가있습니다. 이것은우리가입력했던 id 와 password 를가리키는것으로서입력한내용들이 userid 와 passwd 에각각저장이됩니다. 위의형식으로하면 Post 와 Get 방식으로다되는데요. Request.Form 은 Post 방식, Request.QueryString 는 Get 방식입니다. 물론둘다사용할것이면 Request.Params[Value], Request[Value] 으로하면됩니다. Post 방식은 URI 의정보들을보이지않게전송하는것이고. Ex) spirit.co.kr/index.aspx?id=1234 의 URI 가 spirit.co.kr 로만보이고안보이게전부전송. Get 방식은 URI 의정보들을보이게전송하는것입니다. Ex) spirit.co.kr/index.aspx?id=1234 의 URI 가고스란히보임 Request 함수를사용하면편리하다는장점이있지만, 치명적인단점이있습니다. 그것은 Post, Get 을분간없이사용하기에다른공격에도취약합니다. 따라서, 확실히구분해놓고사용하면보안에도좋습니다 ~
자다음으로갑니다. string sqlquery = "select id, pwd from wiseguyz where id='" + userid + "' and pwd ='" + passwd + "'"; S QL Query 문이네요. select id, pwd from wiseguyz where id= userid and pwd= passwd ; 이런문인데요. 그대로쭉쭉해석하시면됩니다. 선택하고싶어 ( 무엇을?) id 와 pwd 를 ( 어디로부터?)wiseguyz 라는 table 로부터 ( 꼭꼭찝어줘 )id 가 userid 이고 pwd 가 passwd 인것을 ~ 만약에 id 와, pwd 가맞다면승인이될것입니다. 근데뭐가잘못된거지? 라고생각하신다면, 잘못된것은없습니다 ~ 맞는형식이예요, 단 ~ 블랙홀이라는것이보이네요. + userid + 와 + passwd + 가서로떨어져있죠? 큰따옴표에씌어져있고요. 여기에어떠한문장을집어넣으면뒤에있는부분이무시가됩니다. 예를들면, 가죽재킷의가격은 100,000 이라고생각해봅시다. 근데가죽재킷의뒤에있는가격표가없다고생각하면, 공짜죠? 공짜입니다 ~ 안구에습기가차는현상을보게될것입니다. 그렇기에 SQL Injection 이무엇이고어떻게방어를해야되는지를알필요가있습니다. 갑자기다른곳으로샜네요.-_-;
아래를보면, 한사이트에서 id 를 admin, pw 를 admin1234 를입력하고전송했습니다. 그런데서버에서는이것이맞는지확인을하고 접근권한이없습니다 라고메시지를 뿜었습니다. 즉, 아이디가틀리거나해당내용이없다는것을의미합니다. ID : admin PW : admin1234 select id, pwd from wiseguyz where id='admin' and pwd ='admin1234' 접근권한이없습니다. 여기서중요한것은 select id, pwd from wiseguyz where id='admin' and pwd ='admin1234'; 이부분을 id 와 password 부분을사용자가악의적인목적으로다음과같이입력했다면? select id, pwd from wiseguyz where id= ; DROP DATABASE wiseguyz -- 이상한코드들은배제하고순수하게만 ~ 본다면 Database 를삭제하는하삼!( 뭘?)wiseguyz 를 ~ 즉, Database 를삭제하는명령입니다. 만약에, 중요한 data 들이있는 database 면어떻게되나요? 그야말로큰일나겠죠 ~? 자신이등록한레포트, 점수, 사내게시판, 초토화입니다. -_ ㅡ ; 이번엔자세히볼까요? 다음페이지를봅시다 ~
: single quotation mark( 홀따옴표 ) 문자열을처리할때사용하는데요. : 홀따옴표가두개면특수문자를처리할때사용이됩니다. ; : semicolon( 세미콜론 ) 문법을끝마칠때사용이됩니다. -- : double dash( 더블대쉬 ) 쿼리의나머지부분을무시하는것을뜻하며간단하게주석이라고생각하면됩니다. 주로많이사용하는것을적어봤습니다. 그럼 ; DROP DATABASE wiseguyz--' 라는의미를정확히집어낼수있겠네요!! 아 ~ 특수문자를허용을하는구나! 하나의문법을마쳤고, 또다른문법이시작함 ~ 그리고 내뒤로어떠한쿼리문도허용하지마 ~ 어때요? 쉽죠? ^^ 다른것으로해보겠습니다. ID : or 1=1 PW : 아무것이나 ~ ID : 'or 1=1-- PW : adf select id, pwd from wiseguyz where id=''or 1=1--' and pwd ='adf' ExceuteScalar : spirito spirito XXXXXX taeyeon XXXXXX wiseguys XXXXXX 위와같은결과가나옵니다. 1=1 은항상참이라는값을가져오게됩니다. 그리고뒤에 query 문은무시하니까
아래와같은것이겠네요. select id, pwd from wiseguyz where id=''or 1=1--' id 와 pwd 를모두출력하겠군요 ~ -_-;; 다른표현식들 ' or 1=1-- " or 1=1-- or 1=1-- ' or 'a'='a " or "a"="a ') or ('a'='a 우선이정도로하고, 이외에도무수히많습니다.-_-; 만약에여러분들이개발을마치고나서아무런문제가없다고판단을한뒤에포장하여 솔루션을고객들에게판매를했습니다. 그리고몇일뒤에고객들은개인정보들이싹빠져나갔다고한뒤법적조취를취하겠 다고합니다. 어떻게하시겠습니까?... 암울하죠..-_- 자이제부터 SQL Injection 으로부터어떻게보호할수있는지알아보도록하겠습니다.
[SQL Injection 방어 ] 이번에는 SQL Injection 방어에대하여설명하도록하겠습니다. SQL Injection 방어에대해서는여러가지의방법들이있겠지만, 근본인소스를수정하는것입니다. 먼저, 어떠한방법들이있는지알아보도록하겠습니다. 1) 유저접근을제한합니다. : 만약에 SERVER에서 System Account(SA) 를사용중이면접근권한이없는유저로사용합니다. SA가있는계정으로 SQL Injection이성공하면컴퓨터가망가질수도있습니다. 2) 특수문자를제거 / 변경합니다. 즉, 사용자의입력값을신뢰해서는안됩니다.\ :, --, select, =, insert, delte etc Ex) String afterchar = basechar.replace(, ) 3) Post로할것인지, Get으로할것인지한가지만정하여사용합니다. 이것저것사용이가능한것으로하면느슨해지기마련입니다. 참고로, Get은하이퍼링크로만사용하고나머지는 POST로사용하는것이좋습니다. 4) 입력값의길이를 8~10 자이내로제한합니다. ( id, password, post. Etc) 5) RequriedFieldValidator 와 RegularExpressionValidator 를사용하여입력값검증을 확인합니다.
ASP.NET (C#) SQL Injection 방어코드샘플 <SqlCommander 사용 > string sqlquery = "select id, pwd from wiseguyz where id=@hid and pwd=@hpwd"; SqlConnection sqlconn = new SqlConnection(connStr); SqlCommand sqlcomm = new SqlCommand(sqlQuery, sqlconn); sqlcomm.parameters.add("@hid", SqlDbType.VarChar, 30); sqlcomm.parameters["@hid"].value = secuid; sqlcomm.parameters.add("@hpwd", SqlDbType.VarChar, 30); sqlcomm.parameters["@hpwd"].value = secupwd; < 특수문자를 NULL 값으로변경 > String chanid = saveid.replace("'",""); 여기까지 SQL Injection 문서를마치도록하겠습니다. 많이부족한점이있지만, 이것을보고 (SQL Injection in ASP.NET ) 앞으로는이런취약성에대하여노출이되지않고, 방어를하여개인정보또는중요한 data들을밖으로ㄴ나가는일이없었으면좋겠습니다. 이문서에대하여, 수정할부분이나추가해야할부분이있으면 이메일로회신해주세요. E-MAIL : admin@spirito.co.kr