2009/05/27 19:53

SQL Injection Blocking

참고사이트 : http://forums.asp.net/t/1254125.aspx


Global.asax의 Application_BeginRequest 메서드를 이용하여 모든 요청에 대하여 필터링 하는 예제 코드입니다.

//연장준비 네임스페이스 추가
using System.Globalization;

//Get, Post, Cookie까지 모두 필터링
protected void Application_BeginRequest(Object sender, EventArgs e)
{
    foreach (string key in Request.QueryString)
       CheckInput(Request.QueryString[key], key);
    foreach (string key in Request.Form)
       CheckInput(Request.Form[key], key);
    foreach (string key in Request.Cookies)
       CheckInput(Request.Cookies[key].Value, key);  
}

//필터링 할 문자열
public static string[] blackList = {"--",";--",";","/*","*/","@@",
              "declare","delete","update","insert", "select",
              "exec", "execute",
              "drop","kill","sysobjects","syscolumns"};

//필터링 제외할 페이지
public static string[] nochkPageList = {"nochk1.aspx", "nochk2.aspx","nochk3.aspx"};

//필터링 제외할 파라메터 KEY값
public static string[] nochkParamList = {"userid","useremail"};

private void CheckInput(string parameterValue, string parameterName)
{
      CompareInfo comparer = CultureInfo.InvariantCulture.CompareInfo;

      bool chk = true;
      for (int j = 0; j < nochkParamList.Length; j++)
      {
           if (parameterName.ToLower() == nochkParamList[j].ToLower())
           {
              chk = false;
           }
      }

      for (int k = 0; k < nochkPageList.Length; k++)
      {
           if (comparer.IndexOf(Request.RawUrl.ToString(),nochkPageList[k],CompareOptions.IgnoreCase) >= 0)
           {
               chk = false;
           }
       }
   
       for (int i = 0; i < blackList.Length; i++)
       {
           if (comparer.IndexOf(parameterValue,blackList[i],CompareOptions.IgnoreCase) >= 0 && chk == true)
           {
                try
                {
                      //Log남기기
                }
                catch{}
                finally
                {
                      Response.Redirect("/Exception.aspx");
                }
           }
      }
}

위 소스에 문제점은 blackList에 정의된 단어가 입력되면 무조건 Exception페이지로 보내버리게 된다.
가령 아이디가 declare라는 고객이있다면 혹은 게시판 제목을 update post라고 작성한다면...
그런 문제점으로 인하여 추가한게 nochkPageList와 nochkParamList이다.
정의된 페이지와 파라메터key값일때는 필터링 하지 않겠다는거다.

여기서 또 문제점은... 기껏 Sql Injection공격을 막는다고 해놓고 필터링 예외페이지와 예외 파라메터라고 정의해놓으면 예외로 지정된 페이지와 파라메터를 타고 공격이 들어온다면 속수무책으로 당할 수 밖에 없다.

그럼 어떻게 하면 보다 완벽한 소스로 구현할 수 있을까?

내일로 미루고... =_=;


Trackback 0 Comment 0
2009/01/23 11:18

Ping Class


서버관리를 하다보면 관리 웹서버의 상태를 확인하기 위해 Ping을 사용할때가 있다.

ping www.daum.net
ping 118.xxx.xxx.xxx

Ping만으로는 구체적인 웹서버의 상태를 확인하기는 힘들지만
간단하게 웹서버 상태를 확인하기 위해서 사용한다.
하지만 서버가 한두대가 아닌 여러대일 경우 매번 command창에서 명령어를 치기에는 요새
손목통증으로 고생하는 나로써는 큰 부담이 아닐 수 없다. =_=;
그리하여 한번 만들어볼까? 생각이 들어서...MSDN을 찾아봤다. 역시나... 없는거 빼고는 다있는 닷넷!!!

Ping Class발견!! 오호.. 이런게 있구나.. 싶어서...(.NET Framework 버전 2.0에서 새로 추가)
[MSDN Ping Class] http://msdn.microsoft.com/ko-kr/library/system.net.networkinformation.ping.aspx

넬름.. 예제코드를 가지고 테스트... 우와~~ 잘된다.!!! 그래서 만들게 된...
하지만.. 웹만 하다보니... =_=;

우선 Ping에 대하여 간단히 설명하면.

Ping은 호스트(서버)와의 데이터 교환을 하는데 이상유무를 확인하기 위한 네트워크 명령어로
일정 크기의 데이터 보내 지정한 서버가 제대로 응답했는지 확인 후 결과를 보여준다.
Ping명령어를 실행했을때 서버의 문제가 없다면 아래와 같은 메세지를 보여줄거다.
Reply from xxx.xxx.xxx.xx: bytes=32 time=15ms TTL=55
Reply from xxx.xxx.xxx.xx: bytes=32 time=15ms TTL=55
대략 위 메시지를 설명하면... 32바이트이 데이터를 보냈으며 15ms의 응답시간이 걸렸다는거다.
그리고 TTL이란 MSDN에서 설명하기를 TTL은 소스와 대상 사이를 이동할 때 노드에서 패킷을 전달할 수 있는 횟수를 정의합니다. 전달 횟수(홉 수라고도 함)가 TTL에 지정된 값을 초과하면 해당 패킷은 전달할 수 없는 패킷으로 간주되어 삭제됩니다.

만약 서버의 문제가 있다면.
Request timed out 라는 메세지를 보여준다.
위와 같은 결과에 대한 메시지를 보내기 위하여 Ping은 ICMP(Internet Control Message Protocol)라는 부수적인 프로토콜을 사용한다.


그럼 한번 만들어보자!

우선 디자인 폼이다.

별거는 없고 주기적으로 Ping을 날리기 위하여 Timer를 추가하였다.

소스는 아래와 같다.
//서버체크 메서드
private void ServerChk()
{
            Ping pingSender = new Ping();
            PingOptions options = new PingOptions();

//데이터를 여러 패킷으로 보낼 수 없을 경우 true이고, 그렇지 않으면 false 기본값은 false입니다.
options.DontFragment = true;

            listResult.Items.Clear();
            // 전송할 32바이트 데이터
            string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
            byte[] buffer = Encoding.ASCII.GetBytes(data);
            int timeout = 120;
            for (int i = 0; i < listIpBox.Items.Count; i++)
            {
                //Send된 작업의 결과 상태 및 데이터에 대한 정보를 제공한다.
                PingReply reply = pingSender.Send(listIpBox.Items[i].ToString(), timeout, buffer, options);
                if (reply.Status == IPStatus.Success)
                    listResult.Items.Add(reply.Address.ToString() + " 정상 status: " + reply.Status.ToString() + " RoundTrip time:" + reply.RoundtripTime + " Time to live: " + reply.Options.Ttl + " Don't fragment: " + reply.Options.DontFragment);
                else
                    listResult.Items.Add(listIpBox.Items[i].ToString() + " 불량 서버상태 : " + reply.Status.ToString());
            }
}

PingReply속성 자세한 내용은  MSDN 참고 =_=;
[MSDN PingReply] http://msdn.microsoft.com/ko-kr/library/system.net.networkinformation.pingreply_members.aspx


        /// <summary>
        /// 아이피 추가
        /// </summary>

        private void btnIpInput_Click(object sender, EventArgs e)
        {
            listIpBox.Items.Add(txtIp.Text);
            txtIp.Text = "";
            txtIp.Focus();
        }
        /// <summary>
        /// 아이피 삭제
        /// </summary>
        private void btnIpRemove_Click(object sender, EventArgs e)
        {
            if (listIpBox.SelectedIndex == -1)
                MessageBox.Show("삭제할 IP Address를 선택해주세요!");
            else
                listIpBox.Items.RemoveAt(listIpBox.SelectedIndex);
        }
        /// <summary>
        /// 시작
        /// </summary>

        private void btnStart_Click(object sender, EventArgs e)
        {
            Regex reg = new Regex(@"^[0-9]");
            if (textBox1.Text == "")
            {
                MessageBox.Show("입력해주세요!!");
                textBox1.Focus();
            }
            else if (!reg.IsMatch(textBox1.Text))
            {
                MessageBox.Show("숫자만 입력");
                textBox1.Focus();
            }
            else if (listIpBox.Items.Count < 1)
            {
                MessageBox.Show("체크할 IP Address를 하나이상 입력해주세요!");
                txtIp.Focus();
            }
            else
            {
                ServerChk();
                timer1.Interval = int.Parse(textBox1.Text) * 1000;
                timer1.Start();
            }
        }
        /// <summary>
        /// 중지
        /// </summary>
        private void btnStop_Click(object sender, EventArgs e)
        {
            timer1.Stop();
        }

완성된 화면...

 그다지 실용적이지는 않지만... 이런것도 있다는 정도만 알아두자.. ^^;

Trackback 0 Comment 0
2009/01/13 19:35

XML XmlAttribute다루기(삭제, 수정, 추가)


Xml원본
<?xml version="1.0" encoding="utf-8" ?>
<basket>
     <item>
          <scene rc="0 0 590 420" embedCount="9">
              <image rc="0 0 590 420" priority="0" />
          </scene>
     </item>
</basket>



1. 속성삭제
  - image노드의 rc속성을 삭제해보자
XmlDocument doc = new XmlDocument();
doc.Load("xml경로");
XmlNode node = doc.SelectSingleNode("/descendant::basket/item/scene/image");
XmlAttributeCollection acxNode = node.Attributes;
if(acxNode.GetNamedItem("rc") != null)
{
     acxNode.Remove((XmlAttribute)acxNode.GetNamedItem("rc"))
}
doc.Save("경로");


2. 속성값 수정
  - image노드의 rc속성값을 변경해보자
XmlDocument doc = new XmlDocument();
doc.Load("xml경로");
XmlNode node = doc.SelectSingleNode("/descendant::basket/item/scene/image");
XmlAttributeCollection acxNode = node.Attributes;
if(acxNode.GetNamedItem("rc") != null)
{
     acxNode.GetNamedItem("rc").Value = "0 0";
}
doc.Save("경로");


3. 속성값 추가
  - image노드에 test노드를 추가해보자
XmlDocument doc = new XmlDocument();
doc.Load("xml경로");
XmlNode node = doc.SelectSingleNode("/descendant::basket/item/scene/image");
XmlAttributeCollection acxNode = node.Attributes;
XmlAttribute newAttr = doc.CreateAttribute("test");
newAttr.Value = "속성값";
acxNode.SetNamedItem(newAttr);
doc.Save("경로");
Trackback 0 Comment 0