차이
문서의 선택한 두 판 사이의 차이를 보여줍니다.
이전 판 | |||
— | guide:asp.net_개발_보안_가이드 [2024/04/04 05:12] (현재) – 바깥 편집 127.0.0.1 | ||
---|---|---|---|
줄 1: | 줄 1: | ||
+ | ====== ASP.NET 개발 보안가이드 ====== | ||
+ | ===== SQL Injection 취약점 ===== | ||
+ | |||
+ | ==== 취약점 상세 내용 및 보안 대책 ==== | ||
+ | 웹 사이트는 DBMS와 연동하므로 웹 어플리케이션에서 사용자의 입력값을 통하여 데이타 트랜잭션이 발생함. 만일 사용자 입력값에 대한 유효성 검증이 누락될 경우, 악의적인 사용자는 정상적인 입력값 대신 SQL 쿼리문이 포함된 조작된 입력값을 전송하여 서버측 쿼리문의 구조를 변경할 수 있으며, 이를 통해서 사용자 인증을 우회하거나 데이터베이스의 정보를 유출시키고 서버의 시스템 명령어를 실행시킬 수도 있음. | ||
+ | |||
+ | ==== 보안 대책 ==== | ||
+ | |||
+ | === 입력제한 === | ||
+ | 유형, 길이, 형식 및 범위 ASP.NET 응용 프로그램에 대한 모든 입력을 확인. 데이터 액세스 쿼리에 사용되는 입력을 제한함으로써, | ||
+ | * 참조 : 입력을 제한하면 허용 문자의 목록을 작성하고, | ||
+ | |||
+ | 가. ASP.NET 웹 페이지 입력 제한 | ||
+ | ASP.NET 웹 페이지에 대한 서버 측 코드를 입력을 제한함. | ||
+ | |||
+ | 예) SSN 값을 ASP.NET에 의해 캡처하여 텍스트 상자의 입력을 제한 | ||
+ | <%@ language=" | ||
+ | <form id=" | ||
+ | < | ||
+ | < | ||
+ | ErrorMessage=" | ||
+ | ControlToValidate=" | ||
+ | ValidationExpression=" | ||
+ | </ | ||
+ | 예) SSN 입력이 같은 HTML 컨트롤과 같은 다른 소스, 쿼리 문자열 매개 변수 또는 쿠키의 경우에는 사용을 제한 | ||
+ | if (Regex.IsMatch(Request.Cookies[" | ||
+ | { | ||
+ | // access the database | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | // handle the bad input | ||
+ | } | ||
+ | 나. 데이터 액세스 코드 입력 제한\\ 데이터 접근 코드의 유효성 검사를 제공 | ||
+ | * 신뢰할 수없는 클라이언트\\ 신뢰할 수없는 소스에서 데이터가 올 수있다 또는 데이터의 유효성을 검사하고 제한될 수 있으므로, | ||
+ | * 라이브러리 코드\\ 데이터 액세스 코드가 여러 응용 프로그램에서 사용하도록 설계된 라이브러리로 패키지화되어 있으면 클라이언트 응용 프로그램에 대한 더 안전한 가정을 만들 수 있기 때문에, 데이터 액세스 코드가 자신의 유효성 검사를 수행. | ||
+ | 예) 데이터 액세스 루틴 전에 SQL 문에서 매개 변수를 사용하여 정규 표현식을 사용하여 입력 매개 변수의 유효성을 검사하는 방법 | ||
+ | using System; | ||
+ | using System.Text.RegularExpressions; | ||
+ | | ||
+ | public void CreateNewUserAccount(string name, string password) | ||
+ | { | ||
+ | // Check name contains only lower case or upper case letters, | ||
+ | // the apostrophe, a dot, or white space. Also check it is | ||
+ | // between 1 and 40 characters long | ||
+ | if ( !Regex.IsMatch(userIDTxt.Text, | ||
+ | throw new FormatException(" | ||
+ | | ||
+ | // Check password contains at least one digit, one lower case | ||
+ | // letter, one uppercase letter, and is between 8 and 10 | ||
+ | // characters long | ||
+ | if ( !Regex.IsMatch(passwordTxt.Text, | ||
+ | @" | ||
+ | throw new FormatException(" | ||
+ | | ||
+ | // Perform data access logic (using type safe parameters) | ||
+ | ... | ||
+ | } | ||
+ | | ||
+ | === 저장 프로 시저의 매개 변수 사용 === | ||
+ | 저장 프로 시저를 사용하면 반드시 SQL 인젝션을 방지하지 않음. 중요한 점은 저장 프로 시저 매개 변수를 사용. 이 매개 변수를 사용하지 않는 경우가 필터링되지 않은 입력을 사용하는 경우이며, | ||
+ | |||
+ | 예) 저장 프로 시저를 호출 | ||
+ | using System.Data; | ||
+ | using System.Data.SqlClient; | ||
+ | | ||
+ | using (SqlConnection connection = new SqlConnection(connectionString)) | ||
+ | { | ||
+ | DataSet userDataset = new DataSet(); | ||
+ | SqlDataAdapter myCommand = new SqlDataAdapter( | ||
+ | " | ||
+ | myCommand.SelectCommand.CommandType = CommandType.StoredProcedure; | ||
+ | myCommand.SelectCommand.Parameters.Add(" | ||
+ | myCommand.SelectCommand.Parameters[" | ||
+ | | ||
+ | myCommand.Fill(userDataset); | ||
+ | } | ||
+ | |||
+ | 가. 매개 변수가있는 저장 프로 시저 응용 프로그램의 사용 검토 | ||
+ | 매개 변수가있는 저장 프로 시저를 사용하여도 반드시 SQL 인젝션을 방지하지 않기 때문에, 저장 프로 시저의 응용 프로그램의 사용을 검토함. | ||
+ | |||
+ | 예) 저장 프로 시저를 사용하는 응용 프로그램 | ||
+ | CREATE PROCEDURE dbo.RunQuery | ||
+ | @var ntext | ||
+ | AS | ||
+ | exec sp_executesql @var | ||
+ | GO | ||
+ | | ||
+ | === 동적 SQL의 매개 변수 사용 === | ||
+ | 저장 프로 시저를 사용할 수 없는 경우 동적 SQL 문을 생성 할 때, 매개 변수를 사용 | ||
+ | |||
+ | 예) 동적 SQL 매개 변수 사용 | ||
+ | using System.Data; | ||
+ | using System.Data.SqlClient; | ||
+ | | ||
+ | using (SqlConnection connection = new SqlConnection(connectionString)) | ||
+ | { | ||
+ | DataSet userDataset = new DataSet(); | ||
+ | SqlDataAdapter myDataAdapter = new SqlDataAdapter( | ||
+ | " | ||
+ | | ||
+ | myCommand.SelectCommand.Parameters.Add(" | ||
+ | myCommand.SelectCommand.Parameters[" | ||
+ | myDataAdapter.Fill(userDataset); | ||
+ | } | ||
+ | | ||
+ | 가. 일괄 처리 매개 변수 사용 | ||
+ | SQL 텍스트 연결시 고유 한 매개 변수 이름을 사용하는 것을 확인하여 작업을 수행함. | ||
+ | |||
+ | 예) 일괄 처리 매개 변수 사용 | ||
+ | using System.Data; | ||
+ | using System.Data.SqlClient; | ||
+ | . . . | ||
+ | using (SqlConnection connection = new SqlConnection(connectionString)) | ||
+ | { | ||
+ | SqlDataAdapter dataAdapter = new SqlDataAdapter( | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | " | ||
+ | | ||
+ | SqlParameter custIDParm = dataAdapter.SelectCommand.Parameters.Add( | ||
+ | " | ||
+ | custIDParm.Value = customerID.Text; | ||
+ | | ||
+ | SqlParameter countryParm = dataAdapter.SelectCommand.Parameters.Add( | ||
+ | " | ||
+ | countryParm.Value = country.Text; | ||
+ | | ||
+ | connection.Open(); | ||
+ | DataSet dataSet = new DataSet(); | ||
+ | dataAdapter.Fill(dataSet); | ||
+ | } | ||
+ | . . . | ||
+ | |||
+ | ===== XSS(Cross-Site Scripting) 취약점 ===== | ||
+ | |||
+ | ==== 취약점 상세 내용 및 보안 대책 ==== | ||
+ | Javascript, Vbscript 등 PC의 웹브라우저에서 실행되는 클라이언트 사이트 스크립트를 다른 사용자의 웹브라우저에서 실행하도록 함으로서 웹 브라우저를 제어하여 PC를 공격하는 취약점을 말함. 공격에 사용되는 유형은 크게 두가지로 분류. | ||
+ | \\ | ||
+ | (1) Reflected XSS | ||
+ | \\ | ||
+ | 이 유형의 XSS는 클라이언트 측에서 전송된 데이터가 서버측에서 즉시 처리된 후 사용자에게 응답으로 전송되는 돌아오는 경우에 해당함. 다음과 같은 상황에서 발생이 가능함. | ||
+ | \\ | ||
+ | * 검색 페이지에서 입력된 검색어가 검색 결과 페이지에 표시되는 경우 | ||
+ | * URL에 포함된 특정 파라미터가 응답 페이지에 hidden 속성으로 포함되어 있는 경우 | ||
+ | 위의 두가지 유형은 본질적으로는 동일한 내용임. | ||
+ | 이러한 유형의 XSS 는 사회 공학적 방법 등을 통해서 공격 스크립트가 포함된 URL을 타인이 실행하도록 유도함으로서 (예를 들면 메신저로 링크를 전송하거나, | ||
+ | 그러나 공공기관이나 금융권과 같이 신뢰도가 중요한 대상인 경우에는 이 유형의 XSS도 모두 제거해야 하며, 그 외에도 대외에 공개된 웹사이트라면 일반적으로 제거하도록 하는 것이 좋음. | ||
+ | \\ | ||
+ | |||
+ | (2) Stored XSS | ||
+ | \\ | ||
+ | 게시판과 같이 사용자가 입력한 정보가 서버측 DB에 저장되어 있다가 타 사용자가 해당 정보를 열람할 때 DB에 저장되어 있는 정보를 가져와 화면에 출력하는 방식의 웹 애플리케이션에서 발생하는 취약점으로서, | ||
+ | 공격자가 XSS를 목적으로 악성 스크립트를 삽입하여 둘 수 있는 위치는 비단 게시판의 글 본문 뿐만 아니라 제목, 작성자 이름, 날짜, 첨부파일 이름 등이 모두 가능하며, | ||
+ | * 게시판 : 제목, 본문, 작성자, 날짜, 첨부파일 이름, 태그, 분류 등 | ||
+ | * 사용자 프로필 : 이름, 닉네임, 주소, 전화번호, | ||
+ | * 기타 사용자가 입력 가능한 모든 데이터 | ||
+ | |||
+ | ==== 보안 대책 ==== | ||
+ | |||
+ | === ASP.NET 요청 유효성 검사가 활성화되어 있는지 확인 === | ||
+ | 기본적으로 요청 유효성 검사는 Machine.config 파일에서 사용할 수 있음. 그 유효성 검사가 현재 서버의 Machine.config 파일에서 활성화되고 응용 프로그램의 Web.config 파일에서 설정을 무시하지 않는지 확인함. | ||
+ | |||
+ | 가. ASP.NET 유효성 검사가 활성화되어 있는지 확인하는 테스트 절차 | ||
+ | |||
+ | 1. 유효성 검사를 비활성화 하여 ASP.NET 페이지를 만들 수 있음. 이렇게 하려면 설정 ValidateRequest를 = " | ||
+ | |||
+ | <%@ Page Language=" | ||
+ | < | ||
+ | < | ||
+ | void btnSubmit_Click(Object sender, EventArgs e) | ||
+ | { | ||
+ | // If ValidateRequest is false, then ' | ||
+ | // If ValidateRequest is true, then ASP.NET returns an exception | ||
+ | Response.Write(txtString.Text); | ||
+ | } | ||
+ | </ | ||
+ | < | ||
+ | <form id=" | ||
+ | < | ||
+ | | ||
+ | < | ||
+ | OnClick=" | ||
+ | Text=" | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | 2. 페이지를 실행함. 그럴 경우 스크립트 때문에 메시지 상자에 txtString를 지나 브라우저에서 클라이언트 측 스크립트로 렌더링됨. | ||
+ | \\ | ||
+ | 3. 설정값이 ValidateRequest = " | ||
+ | |||
+ | A potentially dangerous Request.Form value was detected from the client (txtString="< | ||
+ | | ||
+ | === HTML 출력을 생성 검토 ASP.NET 코드 === | ||
+ | 예) HTML 출력을 생성 검토 ASP.NET 코드 예제 | ||
+ | Response.Write | ||
+ | <% = | ||
+ | === HTML 출력은 입력 매개 변수를 포함 여부 확인 === | ||
+ | 출력은 입력 매개 변수가 포함되어 있는지 여부를 확인하고 디자인 및 당신의 페이지 코드를 분석함. 이러한 매개 변수는 다양한 소스로부터 올 수 있음. | ||
+ | \\ | ||
+ | |||
+ | 예)일반적인 입력 소스 | ||
+ | |||
+ | * Form 필드 | ||
+ | |||
+ | Response.Write(name.Text); | ||
+ | Response.Write(Request.Form[" | ||
+ | Query Strings | ||
+ | Response.Write(Request.QueryString[" | ||
+ | |||
+ | * 쿼리문자열 | ||
+ | |||
+ | Response.Write(Request.QueryString[" | ||
+ | |||
+ | * 데이터베이스 및 데이터 액세스 방법 | ||
+ | |||
+ | SqlDataReader reader = cmd.ExecuteReader(); | ||
+ | Response.Write(reader.GetString(1)); | ||
+ | |||
+ | * 쿠키 컬렉션 | ||
+ | |||
+ | Response.Write( | ||
+ | Request.Cookies[" | ||
+ | |||
+ | * 세션 및 응용 프로그램 변수 | ||
+ | |||
+ | Response.Write(Session[" | ||
+ | Response.Write(Application[" | ||
+ | |||
+ | === 잠재적으로 위험한 HTML 태그와 속성 검토 === | ||
+ | 동적으로 HTML 태그를 생성하고 잠재적으로 안전하지 않은 입력으로 태그 속성을 구성하는 경우, 악의적인 사용자가 사용하기 전에 태그 속성을 HTML로 인코딩해야함. | ||
+ | 예) aspx 페이지에서는 < | ||
+ | <%@ Page Language=" | ||
+ | | ||
+ | < | ||
+ | <form id=" | ||
+ | <div> | ||
+ | Color:& | ||
+ | < | ||
+ | | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | | ||
+ | <script runat=" | ||
+ | private void Page_Load(Object Src, EventArgs e) | ||
+ | { | ||
+ | protected void Button1_Click(object sender, EventArgs e) | ||
+ | { | ||
+ | Literal1.Text = @"< | ||
+ | + Server.HtmlEncode(TextBox1.Text) | ||
+ | + @"""> | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | 가. 잠재적으로 위험한 HTML 태그 | ||
+ | \\ | ||
+ | |||
+ | 예)악의적인 사용자가 스크립트 코드를 삽입 할 수 있는 일반적으로 사용되는 HTML 태그 | ||
+ | * < | ||
+ | * < | ||
+ | * < | ||
+ | * < | ||
+ | * < | ||
+ | * < | ||
+ | * < | ||
+ | * < | ||
+ | * <img> | ||
+ | * < | ||
+ | * < | ||
+ | * < | ||
+ | * < | ||
+ | * < | ||
+ | * < | ||
+ | |||
+ | \\ | ||
+ | 예) HTML 특성을 사용하여 SRC , lowsrc , 스타일 및 HREF 크로스 사이트 스크립팅을 삽입 | ||
+ | <img src=" | ||
+ | <img src=" | ||
+ | <img src=" | ||
+ | \\ | ||
+ | 예) 사용할 수있는 스타일을 다음과 같이 MIME 타입을 변경하여 스크립트를 삽입하는 태그 | ||
+ | <style TYPE=" | ||
+ | alert(' | ||
+ | </ | ||
+ | === 대책 평가 === | ||
+ | 몇 가지 입력을 사용하여 HTML을 생성하는 ASP.NET 코드를 찾을 때, 특정 응용 프로그램에 대한 적절한 대책을 평가 | ||
+ | \\ | ||
+ | |||
+ | 가. HTML 출력을 인코딩 | ||
+ | \\ | ||
+ | 웹 페이지에 텍스트 출력을 작성하고 텍스트를 HTML 특수 문자 (예 : <,>, and & 포함 된 경우 모르는 경우 )를 사용하여 텍스트를 미리 처리 | ||
+ | \\ | ||
+ | 예) 텍스트 사용자 입력, 데이터베이스 또는 로컬 파일에서 온 경우이 작업을 수행 | ||
+ | Response.Write(HttpUtility.HtmlEncode(Request.Form[" | ||
+ | |||
+ | 나. URL의 출력 인코딩 | ||
+ | \\ | ||
+ | 클라이언트 입력을 포함하는 URL 문자열을 반환 | ||
+ | \\ | ||
+ | 예) URL 문자열을 인코딩하는 방법 | ||
+ | Response.Write(HttpUtility.UrlEncode(urlString)); | ||
+ | |||
+ | 다. 필터 사용자 입력 | ||
+ | \\ | ||
+ | 텍스트 입력 필드의 어떤 종류를 예를 들어 HTML 요소의 범위를 수락해야 페이지가 있다면, 페이지에 대해 ASP.NET 유효성 검사를 요청시 비활성화해야함. 이렇게 여러 페이지가있는 경우, 동의 할 경우에만 HTML 요소를 허용하는 필터를 만듬. | ||
+ | \\ | ||
+ | * 안전 제한된 HTML 입력 | ||
+ | - ASP.NET 유효성 검사를 요청시 비활성화 ValidateRequest=" | ||
+ | - 문자열 입력 인코딩 HtmlEncode 방법. | ||
+ | - 사용되는 StringBuilder을 불러오고 교체 선택적으로 허용 할 HTML 요소에 인코딩을 제거하는 방법. |