輸入驗證和表示法問題是由中繼字元、替代編碼和數值表示法引起的。信任輸入會導致安全問題。問題包括:「Buffer Overflows」、「Cross-Site Scripting」攻擊、「SQL Injection」及其他許多問題。
...
String userName = ctx.getAuthenticatedUserName();
String itemName = request.getParameter("itemName");
String query = "FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ itemName + "'";
List items = sess.createQuery(query).list();
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
itemName
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name' OR 'a'='a
」,那麼查詢將變成以下內容:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
會使 where 子句的評估永遠為 True,所以此查詢在邏輯上可等同於以下較簡化的查詢:
SELECT * FROM items;
items
表中的項目,而不考慮指定的擁有者為何。Example 1
中執行的效果。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name'; DELETE FROM items; --
」,那麼查詢將變成以下兩個查詢:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'
Example 1
中的方法。如果攻擊者輸入「name'); DELETE FROM items; SELECT * FROM items WHERE 'a'='a
」字串,將會建立以下三個有效的陳述式:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';
#
字元來做為典型的定義方式,如下所示:
<select id="getItems" parameterClass="MyClass" resultClass="items">
SELECT * FROM items WHERE owner = #userName#
</select>
#
字元表示 iBatis 將使用 userName
變數建立參數化查詢。不過,iBatis 也可讓您使用 $
字元,將變數直接串連至 SQL 陳述式,製造執行 SQL injection 的機會。
<select id="getItems" parameterClass="MyClass" resultClass="items">
SELECT * FROM items WHERE owner = #userName# AND itemname = '$itemName$'
</select>
itemName
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串 name' OR 'a'='a
,那麼查詢將變成以下內容:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
會使 where 子句的評估永遠為 True,所以此查詢在邏輯上可等同於以下較簡化的查詢:
SELECT * FROM items;
items
表中的項目,而不考慮指定的擁有者為何。Example 1
中執行的效果。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name'; DELETE FROM items; --
」,那麼查詢將變成以下兩個查詢:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'
Example 1
中所示的訣竅進行攻擊。如果攻擊者輸入「name'); DELETE FROM items; SELECT * FROM items WHERE 'a'='a
」字串,將會建立以下三個有效的陳述式:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';
...
String userName = ctx.getAuthenticatedUserName();
String itemName = request.getParameter("itemName");
String sql = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ itemName + "'";
Query query = pm.newQuery(Query.SQL, sql);
query.setClass(Person.class);
List people = (List)query.execute();
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
itemName
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name' OR 'a'='a
」,那麼查詢將變成以下內容:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
會使 where 子句的評估永遠為 True,所以此查詢在邏輯上可等同於以下較簡化的查詢:
SELECT * FROM items;
items
表中的項目,而不考慮指定的擁有者為何。Example 1
中執行的效果。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name'; DELETE FROM items; --
」,那麼查詢將變成以下兩個查詢:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'
Example 1
中的方法。如果攻擊者輸入「name'); DELETE FROM items; SELECT * FROM items WHERE 'a'='a
」字串,將會建立以下三個有效的陳述式:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';
owner
與目前已驗證使用者名稱相符的項目。
...
string userName = ctx.getAuthenticatedUserName();
string query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ ItemName.Text + "'";
var items = dataContext.ExecuteCommand<Item>(query);
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
itemName
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name' OR 'a'='a
」,那麼查詢將變成以下內容:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
會使 where 子句的評估永遠為 True,所以此查詢在邏輯上可等同於以下較簡化的查詢:
SELECT * FROM items;
items
表中的項目,而不考慮指定的擁有者為何。Example 1
中執行的效果。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name'); DELETE FROM items; --
」,那麼查詢將變成以下兩個查詢:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'
Example 1
中的方法。如果攻擊者輸入「name'); DELETE FROM items; SELECT * FROM items WHERE 'a'='a
」字串,將會建立以下三個有效的陳述式:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';
#
字元來進行典型定義,如下所示:
<select id="getItems" parameterType="domain.company.MyParamClass" resultType="MyResultMap">
SELECT *
FROM items
WHERE owner = #{userName}
</select>
#
字元表示 MyBatis 將使用 userName
變數建立參數化查詢。不過,MyBatis 也可讓您使用 $
字元,將變數直接串連至 SQL 陳述式,製造執行 SQL injection 的機會。
<select id="getItems" parameterType="domain.company.MyParamClass" resultType="MyResultMap">
SELECT *
FROM items
WHERE owner = #{userName}
AND itemname = ${itemName}
</select>
itemName
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串 name' OR 'a'='a
,那麼查詢將變成以下內容:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
條件會使 WHERE
子句的評估永遠為 True,所以此查詢在邏輯上可等同於以下較簡化的查詢:
SELECT * FROM items;
items
表中的項目,而不考慮指定的擁有者為何。Example 1
中執行的效果。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name'; DELETE FROM items; --
」,那麼查詢將變成以下兩個查詢:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'
Example 1
中所示的訣竅進行攻擊。如果攻擊者輸入「name'); DELETE FROM items; SELECT * FROM items WHERE 'a'='a
」字串,將會建立以下三個有效的陳述式:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';
owner
與目前已驗證使用者名稱相符的項目。
...
string userName = ctx.GetAuthenticatedUserName();
string query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ ItemName.Text + "'";
List items = sess.CreateSQLQuery(query).List();
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
ItemName
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 ItemName
中輸入字串「name' OR 'a'='a
」,那麼查詢將變成以下內容:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
會使 where 子句的評估永遠為 True,所以此查詢在邏輯上可等同於以下較簡化的查詢:
SELECT * FROM items;
items
表中的項目,而不考慮指定的擁有者為何。Example 1
中執行的效果。如果使用者名稱為 wiley
的攻擊者在 ItemName
中輸入字串「name'; DELETE FROM items; --
」,那麼查詢將變成以下兩個查詢:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'
Example 1
中的方法。如果攻擊者輸入「name'; DELETE FROM items; SELECT * FROM items WHERE 'a'='a
」字串,將會建立以下三個有效的陳述式:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';
owner
與目前已驗證使用者名稱相符的項目。
...
string userName = identity.User;
string itemName = apiGatewayProxyRequest.QueryStringParameters['item'];
string statement = $"SELECT * FROM items WHERE owner = '{userName}' AND itemname = '{itemName}'";
var executeStatementRequest = new ExecuteStatementRequest();
executeStatementRequest.Statement = statement;
var executeStatementResponse = await dynamoDBClient.ExecuteStatementAsync(executeStatementRequest);
return displayResults(executeStatementResponse.Items);
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
itemName
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串 name' OR 'a'='a
,那麼查詢將變成以下內容:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
會使 where 子句的評估永遠為 True,所以此查詢在邏輯上可等同於以下較簡化的查詢:owner
與目前已驗證使用者名稱相符的項目。
...
String userName = identity.getUser();
String itemName = apiGatewayProxyRequest.getQueryStringParameters('item');
String statement = String.format("SELECT * FROM items WHERE owner = '%s' AND itemname = '%s'", userName, itemName);
ExecuteStatementRequest executeStatementRequest = new ExecuteStatementRequest();
executeStatementRequest.setStatement(statement);
ExecuteStatementResponse executeStatementResponse = dynamoDBClient.executeStatement(executeStatementRequest);
return displayResults(executeStatementResponse.items());
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
itemName
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串 name' OR 'a'='a
,那麼查詢將變成以下內容:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
會使 where 子句的評估永遠為 True,所以此查詢在邏輯上可等同於以下較簡化的查詢:
...
String userName = ctx.getAuthenticatedUserName();
String itemName = request.getParameter("itemName");
String query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ itemName + "'";
ResultSet rs = stmt.execute(query);
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
itemName
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name' OR 'a'='a
」,那麼查詢將變成以下內容:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
會使 where 子句的評估永遠為 True,所以此查詢在邏輯上可等同於以下較簡化的查詢:
SELECT * FROM items;
items
表中的項目,而不考慮指定的擁有者為何。Example 1
中執行的效果。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name'; DELETE FROM items; --
」,那麼查詢將變成以下兩個查詢:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'
Example 1
中的方法。如果攻擊者輸入「name'); DELETE FROM items; SELECT * FROM items WHERE 'a'='a
」字串,將會建立以下三個有效的陳述式:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';
Example 1
以適用於 Android 平台。
...
PasswordAuthentication pa = authenticator.getPasswordAuthentication();
String userName = pa.getUserName();
String itemName = this.getIntent().getExtras().getString("itemName");
String query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ itemName + "'";
SQLiteDatabase db = this.openOrCreateDatabase("DB", MODE_PRIVATE, null);
Cursor c = db.rawQuery(query, null);
...
mysql_real_escape_string()
) 可阻止部分,但不是所有 SQL injection 弱點。依賴此類編碼函數等同於使用安全性較差的拒絕清單來防止 SQL injection,可能會讓攻擊者修改陳述式的意義或是執行任意 SQL 指令。由於並非隨時都可以靜態確定輸入將在動態解譯程式碼指定段落中的何處顯示,Fortify Secure Coding Rulepacks 可能會將已驗證的動態 SQL 資料呈現為「SQL Injection: Poor Validation」問題,即便驗證足以阻止當前內容中的 SQL Injection 也是如此。mysqli_real_escape_string()
的行為。 SQL 模式設為「NO_BACKSLASH_ESCAPES」時,反斜線字元會被視為正常字元,而不是逸出字元[5]。 由於 mysqli_real_escape_string()
將此納入考量,所以以下查詢容易受到 SQL injection 攻擊,究其原因,是資料庫配置導致 "
不再逸出為 \"
。
mysqli_query($mysqli, 'SET SQL_MODE="NO_BACKSLASH_ESCAPES"');
...
$userName = mysqli_real_escape_string($mysqli, $_POST['userName']);
$pass = mysqli_real_escape_string($mysqli, $_POST['pass']);
$query = 'SELECT * FROM users WHERE userName="' . $userName . '"AND pass="' . $pass. '";';
$result = mysqli_query($mysqli, $query);
...
password
欄位留白並針對 userName
輸入 " OR 1=1;--
,則引號不會逸出並產生如下查詢:
SELECT * FROM users
WHERE userName = ""
OR 1=1;
-- "AND pass="";
OR 1=1
會使 where 子句的評估永遠為 True,且雙連字符號會使陳述式的其餘部分被視為註解,查詢便會從邏輯上等同於以下大為簡化的查詢:
SELECT * FROM users;
owner
與目前已驗證使用者名稱相符的項目。
...
string userName = ctx.getAuthenticatedUserName();
string query = "SELECT * FROM items WHERE owner = '"
+ userName + "' AND itemname = '"
+ ItemName.Text + "'";
IDataReader responseReader = new InlineQuery().ExecuteReader(query);
...
SELECT * FROM items
WHERE owner = <userName>
AND itemname = <itemName>;
itemName
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name' OR 'a'='a
」,那麼查詢將變成以下內容:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name' OR 'a'='a';
OR 'a'='a'
會使 where 子句的評估永遠為 True,所以此查詢在邏輯上可等同於以下較簡化的查詢:
SELECT * FROM items;
items
表中的項目,而不考慮指定的擁有者為何。Example 1
中執行的效果。如果使用者名稱為 wiley
的攻擊者在 itemName
中輸入字串「name'); DELETE FROM items; --
」,那麼查詢將變成以下兩個查詢:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
--'
Example 1
中的方法。如果攻擊者輸入「name'); DELETE FROM items; SELECT * FROM items WHERE 'a'='a
」字串,將會建立以下三個有效的陳述式:
SELECT * FROM items
WHERE owner = 'wiley'
AND itemname = 'name';
DELETE FROM items;
SELECT * FROM items WHERE 'a'='a';
cfgfile
中讀取,並使用 strcpy()
將輸入內容複製到 inputbuf
中。此程式碼錯誤地假設 inputbuf
將永遠包含一個 Null 終端子。
#define MAXLEN 1024
...
char *pathbuf[MAXLEN];
...
read(cfgfile,inputbuf,MAXLEN); //does not null-terminate
strcpy(pathbuf,inputbuf); //requires null-terminated input
...
cfgfile
讀取的資料按預期在磁碟上以 Null 結束,則 Example 1
中的程式碼所執行的操作是準確無誤的。但是如果攻擊者能夠修改輸入的資訊,以使其不包含預期的 null
字元,那麼呼叫 strcpy()
將在記憶體中連續地進行複製,直到遇到任意的 null
字元,複製才會終止。這就可能會導致目標 Buffer Overflow,而且,如果攻擊者可能控制緊跟 inputbuf
的記憶體內容,則應用程式就可能受到 Buffer Overflow 攻擊。readlink()
擴展了儲存在緩衝區 path
上的符號連結的名稱,使緩衝區 buf
包含符號連結所參照之檔案的絕對路徑。而最終長度值將由 strlen()
來計算。
...
char buf[MAXPATH];
...
readlink(path, buf, MAXPATH);
int length = strlen(buf);
...
Example 2
中的程式碼所執行的操作將會出錯,這是因為藉由 readlink()
讀入 buf
的值將不會以 Null 結束。在測試過程中,類似於這樣的弱點可能不會被捕捉到,因為 buf
中未使用的內容或是對這些內容進行即時跟蹤的記憶體可能都是 null
,因此使得 strlen()
看上去似乎執行了正確的操作。然而在一般情況下,strlen()
將持續橫越記憶體,直到在堆疊中遇到任意的 null
字元才會終止,這就會使 length
的值遠遠大於實際 buf
的大小,進而在隨後的使用過程中可能會造成 Buffer Overflow。snprintf()
複製使用者輸入字串,然後將其放入多個輸出字串中。儘管提供了額外的護欄,但與 sprintf()
相比,特別是最大輸出尺寸的規格,當指定的輸出大小大於預期輸入時,snprintf()
函數仍然容易受到字串終止錯誤的影響。字串終止錯誤可能會導致下游問題,例如記憶體洩漏或緩衝區溢位。
...
char no_null_term[5] = getUserInput();
char output_1[20];
snprintf(output_1, 20, "%s", no_null_term);
char output_2[20];
snprintf(output_2, 20, "%s", no_null_term);
printf("%s\n", output_1);
printf("%s\n", output_2);
...
Example 3
中的程式碼說明了記憶體洩漏。當 output_2
以 no_null_term
填入時,snprintf()
必須從 no_null_term
的位置讀取直到遇到 Null 字元或達到指定的大小限制為止。由於 no_null_term
中沒有終止,因此 snprintf
會繼續讀入 output_1
的資料,最終到達第一次呼叫 snprintf()
所提供的 Null 終止字元。記憶體洩漏的情況透過 output_2
的 printf()
得到印證,其中包含兩次 no_null_term
的字元順序。null
字元做為結束。以前的字串處理方法通常就是依賴此 null
字元來決定字串的長度。如果將不包含 Null 終端子的緩衝區資訊傳送給這樣一個函數,此函數讀取的內容將不只是這個緩衝區資訊。ActionClass-validation.xml
中有多個欄位驗證器定義使用相同名稱。相同名稱的重複驗證定義,會導致運作方式不正常。
<field name="emailField">
<field-validator type="email" short-circuit="true">
<message>You must enter a value for email.</message>
</field-validator>
<field-validator type="email" short-circuit="true">
<message>Not a valid email.</message>
</field-validator>
</field>
validators.xml
發現超過一個驗證器參照。多個相同名稱的驗證定義,會導致運作方式不正常。validators.xml
中,才能用於動作驗證器定義。若有驗證器定義遺失,表示驗證方式不是最新的。validators.xml
中找不到下列動作驗證器。
<validators>
<validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>
</validators>
<form-validation>
<formset>
<form name="ProjectForm">
...
</form>
<form name="ProjectForm">
...
</form>
</formset>
</form-validation>