Dreamweaver 8.0.2 및 CS3의 표준 recordset 내에서 동적 SQL 매개 변수 사용

내용

데이터베이스 보안 취약성 해결

Dreamweaver 8.0.2 및 CS3의 보안을 강화하기 위해 표준 recordset 내에서 동적 SQL 매개 변수를 사용하는 기능을 제거했습니다. 원본 코드는 데이터베이스를 SQL 삽입에 노출했습니다. ASP_VBS 및 ColdFusion 서버 모델에 대해 준비된 명령문을 사용하면 보안 취약성이 해결됩니다. 첫 번째 recordset가 적용된 경우 페이지에 함수를 추가한 다음 PHP_MySQL용 페이지의 모든 recordset에서 해당 함수를 호출해야 했습니다. 이 기법은 ASP_VBS 및 ColdFusion의 준비된 명령문과 유사합니다.

보안 취약성을 막기 위한 노력으로 보안에 대한 약간의 유연성을 교환하였습니다. 동적 SQL 쿼리를 처리해야 하는 확장 프로그램을 이미 보유하고 있거나 개발할 계획인 개발자와 recordset를 사용자 정의하려는 최종 사용자가 동적 매개 변수를 수용하도록 할 수 있고 Dreamweaver 내에서 이러한 사용자 정의 recordset를 편집할 수 있는 기능을 제공할 수 있습니다.

SQL 삽입 및 예방 방법

SQL 삽입은 응용 프로그램의 데이터베이스 레이어에서 발생하는 보안 취약성을 악용하는 기법입니다. SQL 문에 포함된 문자열 리터럴 이스케이프 문자에 대해 사용자 입력이 잘못 필터링되거나 사용자 입력이 강력하게 입력되지 않아 예기치 않게 실행되는 경우 이 취약성이 발생합니다. 사실 하나의 프로그래밍 또는 스크립팅 언어가 다른 프로그래밍 언어 내에 포함될 때마다 발생할 수 있는 더욱 일반적인 취약성 등급의 인스턴스입니다. 자세한 내용은 위키피디아를 참조하십시오.

표준 SQL 쿼리 예제:

SELECT * FROM company_com WHERE name_com = '$companyName'

위의 예에서 $companyName 변수는 입력 양식 필드에서 읽으므로 사용자는 어떤 값을 전송할지 완전하게 제어할 수 있습니다. 최상의 시나리오에서 사용자가 회사 이름에 해당하는 입력에서 "Adobe"(따옴표 없이)를 입력하면 지정된 SQL 쿼리는 다음과 같이 표시됩니다.

SELECT * FROM company_com WHERE name_com = 'Adobe'

그러나 사용자가 웹 사이트를 삭제하고 중요한 정보를 도용하거나 데이터베이스를 폐기하려는 경우가 있습니다. 위의 예를 들어 SQL 삽입은 "blabla" OR '1'='1" 문자열(주변 따옴표 없음)을 입력하면 쉽게 달성할 수 있습니다. 이 문자 순서를 지정하면 사용자는 단일 회사 대신 모든 회사에 액세스할 수 있습니다. 실행되는 실제 SQL은 다음과 같습니다.

SELECT * FROM company_com WHERE name_com = 'blabla' OR '1'='1'

또한 사용자가 전체 company_com 표를 삭제하려는 경우 다음 문자열 "x'를 전달하면 이 작업을 수행할 수 있습니다; DROP TABLE company_com; —"(주변 따옴표 제외). 다음은 전체 SQL 쿼리입니다.

SELECT * FROM company_com WHERE name_com = 'x'; DROP TABLE company_com; --'

다음 방법 중 하나를 사용하여 SQL 삽입으로부터 웹 사이트를 보호합니다.

  • 지정된 범위를 벗어나는 다른 모든 문자를 자동으로 제거하여 허용되는 최소 문자 집합으로 입력을 제한합니다.
  • SQL 쿼리(예: 작은따옴표)에서 사용할 때 문제를 일으킬 수 있는 모든 문자를 이스케이프 처리합니다.
  • 준비된 명령문을 사용합니다.
  • 데이터베이스 액세스 권한을 사용합니다.
  • 저장된 프로시저를 사용합니다.

준비된 명령문 사용에 상세히 설명되어 있는 준비된 명령문을 권장합니다. Dreamweaver 8.0.2 및 CS3에서는 ASP_VBS, ASP_JavaScript, Cold Fusion 및 JSP 서버 모델에 대해 준비된 명령문 접근 방식을 사용하고 PHP_MySQL 서버 모델에 대한 사용자 입력 방식을 이스케이프 처리합니다. SQL 삽입 공격에 대한 자세한 내용은 SQL 삽입 공격 예를 참조하십시오.

준비된 명령문 사용

Dreamweaver 8.0.2 및 CS는 이 솔루션을 사용하여 URL을 통해 전송할 수 있는 지정된 값으로 실제 SQL 매개 변수를 교체할 수 있으며, 페이지가 아니라 서버에서 수행되므로 준비된 명령문을 사용합니다. 또한 준비된 명령문은 SQL 자체에 전달된 값이 적절한 데이터 유형을 가지고 있으며 적절한 이스케이프 유형을 사용한다는 것을 보증합니다. 매개 변수가 int 유형인 경우 사용자가 편지를 제출할 수 없거나 매개 변수가 텍스트 유형인 경우 전달된 전체 문자열이 제대로 이스케이프되고 사용자는 SQL 삽입 작업을 수행할 수 없습니다.

ASP_VBS 및 ASP_JS 서버 모델에 대해 준비된 명령문

ASP_VBS 및 ASP_JS의 경우 ADODB 데이터베이스 레이어를 사용합니다. 다음 예제에서는 동적 SQL 매개 변수를 사용하여 결과를 필터링하는 간단한 ASP_VBS 레코드세트를 보여 줍니다.

... <% Dim Recordset1__MMColParam Recordset1__MMColParam = "1" If (Request.QueryString("id_com") <> "") Then Recordset1__MMColParam = Request.QueryString("id_com") End If %> <% Dim Recordset1 Dim Recordset1_cmd Dim Recordset1_numRows Set Recordset1_cmd = Server.CreateObject ("ADODB.Command") Recordset1_cmd.ActiveConnection = MM_connContacts_STRING Recordset1_cmd.CommandText = "SELECT * FROM company_com WHERE id_com = ?" Recordset1_cmd.Prepared = true Recordset1_cmd.Parameters.Append Recordset1_cmd.CreateParameter("param1", 5, 1, -1, Recordset1__MMColParam) ' adDouble Set Recordset1 = Recordset1_cmd.Execute Recordset1_numRows = 0 %> ...

ColdFusion 서버 모델에 대해 준비된 명령문

ColdFusion은 준비된 명령문을 기본적으로 지원합니다. 다음 예제에서는 동적 SQL 매개 변수를 사용하여 결과를 필터링하는 간단한 ColdFusion 레코드세트를 보여 줍니다.

... <cfparam name="URL.id_com" default="1"> <cfquery name="Recordset1" datasource="company_employee"> SELECT * FROM company_com WHERE id_com = <cfqueryparam value="#URL.id_com#" cfsqltype="cf_sql_numeric"> </cfquery> ...

PHP_MySQL 서버 모델에 대해 준비된 시뮬레이션된 명령문

MySQL 4.1에서는 PHP에 대해 준비된 명령문을 사용할 수 있게 되었지만 이전 버전의 MySQL도 지원할 수 있도록 거의 동일한 기능을 수행하는 사용자 정의 함수를 구현하기로 했습니다. 다음 예제에서는 동적 SQL 매개 변수를 사용하여 결과를 필터링하는 간단한 PHP 레코드세트를 보여 줍니다.

... <?php if (!function_exists("GetSQLValueString")) { function GetSQLValueString($theValue, $theType, $theDefinedValue = "", $theNotDefinedValue = "") { $theValue = get_magic_quotes_gpc() ? stripslashes($theValue) : $theValue; $theValue = function_exists("mysql_real_escape_string") ? mysql_real_escape_string($theValue) : mysql_escape_string($theValue); switch ($theType) { case "text": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "long": case "int": $theValue = ($theValue != "") ? intval($theValue) : "NULL"; break; case "double": $theValue = ($theValue != "") ? "'" . doubleval($theValue) . "'" : "NULL"; break; case "date": $theValue = ($theValue != "") ? "'" . $theValue . "'" : "NULL"; break; case "defined": $theValue = ($theValue != "") ? $theDefinedValue : $theNotDefinedValue; break; } return $theValue; } } $colname_Recordset1 = "-1"; if (isset($_GET['id_com'])) { $colname_Recordset1 = $_GET['id_com']; } mysql_select_db($database_connContacts, $connContacts); $query_Recordset1 = sprintf("SELECT * FROM company_com WHERE id_com = %s", GetSQLValueString($colname_Recordset1, "int")); $Recordset1 = mysql_query($query_Recordset1, $connContacts) or die(mysql_error()); $row_Recordset1 = mysql_fetch_assoc($Recordset1); $totalRows_Recordset1 = mysql_num_rows($Recordset1); ?> ...

표준 recordset에서 동적 매개 변수 허용

따라서 동적 매개 변수를 허용하고 결과 코드를 Dreamweaver의 서버 동작 패널을 통해 편집 가능하게 유지하면서 SQL 삽입을 방지하려면 어떻게 해야 합니까? 이 방법은 동적 매개 변수를 클래식 SQL 매개 변수로 전달하지 않고 SQL 쿼리 자체에 삽입합니다. 이 매개 변수는 준비된 명령문을 통해 이스케이프되거나 SQL에 추가됩니다.

중요: 사용자는 Dreamweaver 8.0.2 또는 CS3과 함께 제공되는 개체 및 서버 동작을 사용하여 이러한 코드를 생성할 수 없습니다(예: 서버 동작 패널 또는 삽입 막대를 통해 레코드세트 삽입). 이 솔루션을 사용하려면 사용자가 코드를 수동으로 편집하거나 이러한 코드를 만드는 타사 확장 프로그램을 설치해야 합니다. 보안 코드 작성 책임은 사용자 또는 타사 소프트웨어 개발자에게 있습니다.

이 방법의 목적은 숙련된 개발자가 동적 SQL 쿼리를 만들 수 있도록 하는 것입니다. 이러한 솔루션을 잘못 사용하면 해커는 원치 않는 권한을 받거나 웹 페이지와 데이터베이스를 분리할 수 있습니다. SQL 삽입의 위험을 최소화하려면 SQL 삽입 및 예방 방법을 참조하십시오.

이 솔루션이 사용되는 주요 사례는 다음과 같습니다.

  • 동적 매개 변수를 허용하도록 SQL 쿼리를 수동으로 만들거나 업데이트합니다.
  • 기존 확장 프로그램을 만들거나 업그레이드하여 동적 매개 변수를 생성합니다.

두 사용 사례는 모두 다음 단락에 자세히 설명되어 있습니다.

Dreamweaver 내에서 레코드세트를 계속 편집할 수 있게 하면서 동적 매개 변수를 허용하도록 SQL 쿼리를 수동으로 생성/업데이트

다음 예제에서는 사용자가 동적 테이블에 정렬 기능을 추가하려고 합니다. 파일 전달 시 페이지를 다시 로드하고 URL에서 사용할 정렬 방향(오름차순 또는 내림차순)을 결정합니다. 초기 URL 예제는 다음과 같습니다.

http://www.mydomain.com/index.php?sortCol=name_com&sortDir=asc

서버 동작을 사용하여 Dreamweaver에서 이 작업을 수행하려면 직접 코딩해야 합니다. 다음 코드 샘플에서는 각 서버 모델에 대해 만들어야 하는 변경 사항을 보여 줍니다.

중요: 아래 예제는 SQL 삽입에 대한 유효성 검사를 하지 않습니다. 해당 역할은 순수한 교육 과정이므로 있는 그대로 제작에 사용되지는 않습니다. 예는 가능한 한 단순하게 유지하기 위한 글머리 기호가 아닙니다. SQL 삽입에 대해 보호해야 합니다. 자세한 내용은 SQL 삽입 및 예방 방법을 참조하십시오.

ASP_VBS

개선 전:

... <% Dim Recordset1 Dim Recordset1_cmd Dim Recordset1_numRows Set Recordset1_cmd = Server.CreateObject ("ADODB.Command") Recordset1_cmd.ActiveConnection = MM_connContacts_STRING Recordset1_cmd.CommandText = "SELECT * FROM company_com" Recordset1_cmd.Prepared = true Set Recordset1 = Recordset1_cmd.Execute Recordset1_numRows = 0 %> ...

다음 이후:

... <% Dim orderBy: orderBy = "" If (Request.QueryString("sortCol") <> "") Then orderBy = "ORDER BY " & Request.QueryString("id_com") If (Request.QueryString("sortDir") <> "") Then orderBy = orderBy & " " & Request.QueryString("sortDir") End If End If %> <% Dim Recordset1 Dim Recordset1_cmd Dim Recordset1_numRows Set Recordset1_cmd = Server.CreateObject ("ADODB.Command") Recordset1_cmd.ActiveConnection = MM_connContacts_STRING Recordset1_cmd.CommandText = "SELECT * FROM company_com " & orderBy & "" Recordset1_cmd.Prepared = true Set Recordset1 = Recordset1_cmd.Execute Recordset1_numRows = 0 %> ...

ColdFusion

개선 전:

... <cfquery name="Recordset1" datasource="company_employee"> SELECT * FROM company_com </cfquery> ...

다음 이후:

... <cfparam name="URL.sortCol" default=""> <cfparam name="URL.sortDir" default="ASC"> <cfset orderBy=""> <cfif (#URL.sortCol# NEQ "")> <cfset orderBy="ORDER BY #URL.sortCol# #URL.sortDir#"> </cfif> <cfquery name="Recordset1" datasource="company_employee"> SELECT * FROM company_com #orderBy# </cfquery> ...

PHP_MySQL

개선 전:

... <?php mysql_select_db($database_connContacts, $connContacts); $query_Recordset1 = "SELECT * FROM company_com"; $Recordset1 = mysql_query($query_Recordset1, $connContacts) or die(mysql_error()); $row_Recordset1 = mysql_fetch_assoc($Recordset1); $totalRows_Recordset1 = mysql_num_rows($Recordset1); ?> ...

다음 이후:

... <?php $orderBy = ""; if (isset($_GET['sortCol'])) { $orderBy = "ORDER BY " . $_GET['sortCol']; if (isset($_GET['sortDir'])) { $orderBy .= " " . $_GET['sortDir']; } } ?> <?php mysql_select_db($database_connContacts, $connContacts); $query_Recordset1 = "SELECT * FROM company_com " . $orderBy . ""; $Recordset1 = mysql_query($query_Recordset1, $connContacts) or die(mysql_error()); $row_Recordset1 = mysql_fetch_assoc($Recordset1); $totalRows_Recordset1 = mysql_num_rows($Recordset1); ?> ...

기존 확장 프로그램 생성/업그레이드를 통해 Dreamweaver 내에서 레코드세트를 편집할 수 있는 상태로 유지하면서 동적 매개 변수를 생성할 수 있습니다.

이제 사용자가 내장된 기능과 수동 편집의 조합을 사용하는 대신 적절한 코드를 생성하는 확장을 만들려는 경우를 제외하고는 위와 동일한 시나리오를 생각해 보십시오. 새 확장 프로그램은 ASP_VBS, ColdFusion 및 PHP_MySQL 서버 모델에 대한 올바른 코드를 생성해야 합니다.

중요: 다음 섹션에서는 동적 SQL 쿼리를 만들기 위해 URL 매개 변수의 값을 사용하는 코드를 생성하는 데만 중점을 둡니다. 주요 초점은 코드를 생성하여 Dreamweaver에서 계속 인식되고 표준 Dreamweaver 인터페이스 내에서 편집할 수 있도록 하는 것입니다. 이 자습서에서는 입력 데이터의 유효성 검사(URL 매개 변수 사용)를 처리하거나 SQL 삽입 시도로부터 최종 SQL을 보호하지 않습니다. 이러한 코드의 복잡성은 이 자습서의 범위를 벗어나기 때문입니다. 개발자는 SQL 삽입으로부터 최종 SQL을 보호할 단독 책임이 있습니다.

연결과 표를 입력으로 가져와 모든 레코드를 표시하도록 동적 표를 생성하는 데모 확장 프로그램을 제공합니다. 또한 위의 예제에 표시된대로 생성된 SQL이 orderBy 변수를 포함하도록 업데이트됩니다. 이 확장 프로그램은 Dreamweaver 8.0.2 및 CS3용으로 설계되었습니다. 생성된 코드는 표준 Dreamweaver 인터페이스를 사용하여 편집할 수 있는 동적 매개 변수를 포함하는 recordset를 만드는 것이 목적이므로 글머리 기호 교정이 아닙니다. 확장 소스 코드는 사용자의 구성 폴더에 있습니다.

아래의 모든 코드 예제에서 강조 표시된 섹션은 URL 매개 변수 sortColsortDir을 통해 정렬 기능을 사용하도록 추가되었습니다.

ASP_VBS

ASP_VBS 서버 모델에 적합한 SQL 쿼리를 생성하는 코드는 사용자 구성 폴더의 "[USER_CONFIGURATION_FOLDER]/Commands/My Dynamic Table.js" 파일 내에 있습니다. 130번 행에 눈에 띄는 변화가 있습니다.

... 130: paramObj.encodedSQL = "SELECT * FROM " + paramObj.table + " \" & orderBy & \""; ...

MyDynamicTable ASP_VBS 서버 동작의 참여자 파일에는 페이지에 "orderBy" 변수 정의를 추가하는 추가 참여자가 포함되어 있습니다.

<group name="MyDynamicTable" version="9.0"> <groupParticipants> <groupParticipant name="connectionref_statement" /> <groupParticipant name="MyDynamicTable_orderBy" /> <groupParticipant name="recordset_main" /> <groupParticipant name="repeatedRegion_init2" /> <groupParticipant name="DynamicTable_main" /> <groupParticipant name="recordset_close" /> </groupParticipants> </group>

ColdFusion

사용자 구성 폴더의 동일한 "[USER_CONFIGURATION_FOLDER]/Commands/My Dynamic Table.js"에는 ColdFusion 서버 모델에 대한 코드도 포함되어 있습니다. 이 경우 관련 변경 사항은 138번 행에 있습니다.

... 138: paramObj.SQLStatement = "SELECT * FROM " + paramObj.table + " #orderBy#"; ...

MyDynamicTable ColdFusion 서버 동작의 참여자 파일에는 페이지에 "orderBy" 변수 정의를 추가하는 추가 참여자가 포함되어 있습니다.

<group name="MyDynamicTable" version="9.0"> <groupParticipants> <groupParticipant name="MyDynamicTable_orderBy" /> <groupParticipant name="Recordset_main" /> <groupParticipant name="DynamicTable_main" /> <groupParticipant name="RepeatedRegion_pageNum" /> <groupParticipant name="RepeatedRegion_maxRows" /> <groupParticipant name="RepeatedRegion_startRow" /> <groupParticipant name="RepeatedRegion_endRow" /> <groupParticipant name="RepeatedRegion_totalPages" /> </groupParticipants> </group>

PHP_MySQL

확장 프로그램의 마지막 서버 모델은 PHP_MySQL입니다. 사용자 구성 폴더의 "[USER_CONFIGURATION_FOLDER]/Commands/My Dynamic Table.js" 파일에 있는 관련 변경 사항은 122번 행에 있습니다.

... 122: paramObj.SQLStatement = "SELECT * FROM " + paramObj.table+ " \" . $orderBy . \""; ...

MyDynamicTable PHP_MySQL 서버 동작의 참여자 파일에는 페이지에 "orderBy" 변수 정의를 추가하는 추가 참여자가 포함되어 있습니다.

<group name="MyDynamicTable" version="9.0"> <groupParticipants> <groupParticipant name="Connection_include" /> <groupParticipant name="MyDynamicTable_orderBy" /> <groupParticipant name="EditOps_SQLValueString" /> <groupParticipant name="Recordset_main" /> <groupParticipant name="DynamicTable_main" /> <groupParticipant name="Recordset_close" /> </groupParticipants> </group>

장점

위에서 설명한 방법에는 다음과 같은 몇 가지 장점이 있습니다.

  • 고급 개발자는 SQL 삽입 취약성을 활용하여 보다 복잡한 SQL을 동적으로 구성할 수 있습니다.
  • 생성된 recordset는 Dreamweaver 내에서 계속 편집할 수 있습니다.
  • 동적 SQL 매개 변수를 사용하여 recordset를 생성하는 기존 Dreamweaver 확장 프로그램에는 통합하기가 어렵지 않습니다.
  • Dreamweaver에서 생성된 기본 코드는 변경되지 않고 그대로 유지됩니다. 동적 쿼리가 필요하지 않은 개발자와 해당 고객은 Dreamweaver에서 작성한 코드가 안전한지 확인할 수 있습니다.

단점

Dreamweaver는 기본적으로 이 방법을 지원하도록 설계되지 않았으므로 다음과 같은 몇 가지 단점이 있습니다.

  • 이 문서에 설명된 방법을 사용하여 생성된 코드는 SQL 삽입에 취약하므로 다른 방법으로 보호해야 합니다. 이러한 보호 방법 목록에는 다음이 포함되지만 이에 국한되지 않습니다.
    • 최종 사용자가 웹 페이지 및/또는 데이터베이스를 구성하는 데 SQL 삽입 방법을 사용할 수 없도록 하십시오.
    • 인수가 실제 SQL에 도달하기 전에 이스케이프 처리합니다.
    • 사용자가 코드를 삭제하더라도 중요한 정보를 도용하지 않거나 데이터베이스를 구성하지 않도록 해야 합니다.
  • 다음 버전의 Dreamweaver가 릴리스될 때까지 수정할 수 없는 두 가지 알려진 문제:
    • ColdFusion: 단순 레코드세트 UI는 편집한 후 다시 적용할 때 SQL 쿼리에서 변수 이름 주위의 해시를 제거합니다
    • ColdFusion, ASP_VBS, ASP_JS: SQL 쿼리에 변수 이름이 포함된 경우 고급 레코드세트 UI의 테스트 버튼이 작동하지 않습니다.

사용자의 구성 폴더 찾기

  • Windows XP

    C:\Documents and Settings\[사용자 이름]\Application Data\Adobe\Dreamweaver 9\Configuration
  • Windows Vista

    C:\Users\[사용자 이름]\AppData\Roaming\Adobe\Dreamweaver 9\Configuration
  • Mac OS 10.4.x

    /Users/[사용자 이름]/Library/Application\ Support/Adobe/Dreamweaver\ 9/Configuration

쉽고 빠르게 지원 받기

신규 사용자이신가요?