RegisterModel
或 Details
類別中的任何屬性:
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
try
{
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", "");
}
}
return View(model);
}
RegisterModel
類別定義為:
public class RegisterModel
{
[BindRequired]
[Display(Name = "User name")]
public string UserName { get; set; }
[BindRequired]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
public string ConfirmPassword { get; set; }
public Details Details { get; set; }
public RegisterModel()
{
Details = new Details();
}
}
Details
類別定義為:範例 2:在 ASP.NET MVC 或 Web API 應用程式中使用
public class Details
{
public bool IsAdmin { get; set; }
...
}
TryUpdateModel()
或 UpdateModel()
時,模型繫結器會根據預設,自動嘗試繫結所有 HTTP 要求參數:範例 3:在 ASP.NET 網頁表單應用程式中,使用
public ViewResult Register()
{
var model = new RegisterModel();
TryUpdateModel<RegisterModel>(model);
return View("detail", model);
}
TryUpdateModel()
或 UpdateModel()
搭配 IValueProvider 介面時,模型繫結器會自動嘗試繫結所有 HTTP 要求參數。
Employee emp = new Employee();
TryUpdateModel(emp, new System.Web.ModelBinding.FormValueProvider(ModelBindingExecutionContext));
if (ModelState.IsValid)
{
db.SaveChanges();
}
Employee
類別定義為:
public class Employee
{
public Employee()
{
IsAdmin = false;
IsManager = false;
}
public string Name { get; set; }
public string Email { get; set; }
public bool IsManager { get; set; }
public bool IsAdmin { get; set; }
}
Booking
類別中的任何屬性:
<view-state id="enterBookingDetails" model="booking">
<on-render>
<render fragments="body" />
</on-render>
<transition on="proceed" to="reviewBooking">
</transition>
<transition on="cancel" to="cancel" bind="false" />
</view-state>
Booking
類別定義為:
public class Booking implements Serializable {
private Long id;
private User user;
private Hotel hotel;
private Date checkinDate;
private Date checkoutDate;
private String creditCard;
private String creditCardName;
private int creditCardExpiryMonth;
private int creditCardExpiryYear;
private boolean smoking;
private int beds;
private Set<Amenity> amenities;
// Public Getters and Setters
...
}
Order
、Customer
和 Profile
都是 Microsoft .NET 實體持續性類別。
public class Order {
public string ordered { get; set; }
public List<LineItem> LineItems { get; set; }
pubilc virtual Customer Customer { get; set; }
...
}
public class Customer {
public int CustomerId { get; set; }
...
public virtual Profile Profile { get; set; }
...
}
public class Profile {
public int profileId { get; set; }
public string username { get; set; }
public string password { get; set; }
...
}
OrderController
則是處理要求的 ASP.NET MVC 控制項類別:
public class OrderController : Controller{
StoreEntities db = new StoreEntities();
...
public String updateOrder(Order order) {
...
db.Orders.Add(order);
db.SaveChanges();
}
}
Order
、Customer
及 Profile
都是 Hibernate 持續性類別。
public class Order {
String ordered;
List lineItems;
Customer cust;
...
}
public class Customer {
String customerId;
...
Profile p;
...
}
public class Profile {
String profileId;
String username;
String password;
...
}
OrderController
則是處理要求的 Spring 控制項類別:
@Controller
public class OrderController {
...
@RequestMapping("/updateOrder")
public String updateOrder(Order order) {
...
session.save(order);
}
}
Register
) 會從網頁表單存取,此表單會要求使用者提供名稱及密碼來註冊帳戶:
public ActionResult Register(RegisterModel model)
{
if (ModelState.IsValid)
{
try
{
return RedirectToAction("Index", "Home");
}
catch (MembershipCreateUserException e)
{
ModelState.AddModelError("", "");
}
}
return View(model);
}
RegisterModel
類別定義為:
public class RegisterModel
{
[BindRequired]
[Display(Name = "User name")]
public string UserName { get; set; }
[BindRequired]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
public string ConfirmPassword { get; set; }
public Details Details { get; set; }
public RegisterModel()
{
Details = new Details();
}
}
Details
類別定義為:
public class Details
{
public bool IsAdmin { get; set; }
...
}
Example 1
中的情況,攻擊者可能會探索應用程式並發現 RegisterModel
模型中有一個 Details
屬性。若是如此,攻擊者接著可能會嘗試覆寫指派給其屬性的目前值。
name=John&password=****&details.is_admin=true
<struts-config>
<form-beans>
<form-bean name="dynaUserForm"
type="org.apache.struts.action.DynaActionForm" >
<form-property name="type" type="java.lang.String" />
<form-property name="user" type="com.acme.common.User" />
</form-bean>
...
User
類別定義為:
public class User {
private String name;
private String lastname;
private int age;
private Details details;
// Public Getters and Setters
...
}
Details
類別定義為:
public class Details {
private boolean is_admin;
private int id;
private Date login_date;
// Public Getters and Setters
...
}
Example 1
中的情況,攻擊者可能會探索應用程式並發現 User
模型中有一個 details
屬性。若是如此,攻擊者接著可能會嘗試覆寫指派給其屬性的目前值。
type=free&user.name=John&user.lastname=Smith&age=22&details.is_admin=true
null
的函數回傳值。Equals()
成員函數前,不會檢查 Item
屬性回傳的字串是否為 null
,可能會造成 null
解除參照。
string itemName = request.Item(ITEM_NAME);
if (itemName.Equals(IMPORTANT_ITEM)) {
...
}
...
null
值都沒有關係。null
的函數回傳值。malloc()
回傳的指標之前,並不會檢查記憶體是否已成功分配。
buf = (char*) malloc(req_size);
strncpy(buf, xfer, req_size);
malloc()
呼叫的失敗是由於 req_size
太大,或者因為在同一時刻有太多的要求需要被處理?或者是由於建立已久的記憶體洩露所引起的?若不處理此錯誤,我們將永遠不知道答案。null
的函數回傳值。compareTo()
成員函數前,不會檢查 getParameter()
傳回的字串是否為 null
,可能會造成 null
解除參照。範例 2:以下程式碼顯示,設定為
String itemName = request.getParameter(ITEM_NAME);
if (itemName.compareTo(IMPORTANT_ITEM)) {
...
}
...
null
的系統特性,之後被程式設計人員錯誤地假設為始終會被定義,因而被解除參照。
System.clearProperty("os.name");
...
String os = System.getProperty("os.name");
if (os.equalsIgnoreCase("Windows 95") )
System.out.println("Not supported");
null
值都沒有關係。null
作比較,但是卻違反了這個規定。Object.equals()
、Comparable.compareTo()
和 Comparator.compare()
方法時,如果其參數為 null
,則必須傳回指定的值。若沒有遵守這個規定,將會導致無法預期的結果。equals()
方法的實作,不會將其參數與 null
比較。
public boolean equals(Object object)
{
return (toString().equals(object.toString()));
}
FormAction
,但無法按照預期的要求驗證資料:範例 2:以下程式碼定義了 Spring WebFlow 動作狀態,但無法按照預期的要求驗證資料:
<bean id="customerCriteriaAction" class="org.springframework.webflow.action.FormAction">
<property name="formObjectClass"
value="com.acme.domain.CustomerCriteria" />
<property name="propertyEditorRegistrar">
<bean
class="com.acme.web.PropertyEditors" />
</property>
</bean>
<action-state>
<action bean="transferMoneyAction" method="bind" />
</action-state>
def form = Form(
mapping(
"name" -> text,
"age" -> number
)(UserData.apply)(UserData.unapply)
)
clone()
方法中也執行相同的檢查。clone()
方法時,不會呼叫正在複製的該類別建構函數。因此,如果可複製類別中的建構函數存有 SecurityManager 或 AccessController 檢查,在該類別的複製方法中也必須存有相同的檢查。否則,複製該類別後,就會略過安全檢查。SecurityManager
檢查,但在 clone()
方法中則沒有此檢查。
public class BadSecurityCheck implements Cloneable {
private int id;
public BadSecurityCheck() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new BadPermission("BadSecurityCheck"));
}
id = 1;
}
public Object clone() throws CloneNotSupportedException {
BadSecurityCheck bsm = (BadSecurityCheck)super.clone();
return null;
}
}
SecurityManager
檢查的可序列化類別必須在其 readObject()
和 readObjectNoData
方法中也執行相同的檢查。readObject()
方法時,不會呼叫該類別正在還原序列化的建構函數。因此,如果可序列化類別中的建構函數存有 SecurityManager
檢查,在 readObject()
與 readObjectNoData()
方式中也必須存有相同的 SecurityManager
檢查。否則,還原序列化該類別後,就會略過安全檢查。SecurityManager
檢查,但在 readObject()
與 readObjectNoData()
方式中則沒有此檢查。
public class BadSecurityCheck implements Serializable {
private int id;
public BadSecurityCheck() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new BadPermission("BadSecurityCheck"));
}
id = 1;
}
public void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException {
in.defaultReadObject();
}
public void readObjectNoData(ObjectInputStream in) throws ClassNotFoundException, IOException {
in.defaultReadObject();
}
}
...
// "type" parameter expected to be either: "Email" or "Username"
string type = request["type"];
string value = request["value"];
string password = request["password"];
var ddb = new AmazonDynamoDBClient();
var attrValues = new Dictionary<string,AttributeValue>();
attrValues[":value"] = new AttributeValue(value);
attrValues[":password"] = new AttributeValue(password);
var scanRequest = new ScanRequest();
scanRequest.FilterExpression = type + " = :value AND Password = :password";
scanRequest.TableName = "users";
scanRequest.ExpressionAttributeValues = attrValues;
var scanResponse = await ddb.ScanAsync(scanRequest);
...
Email = :value AND Password = :password
Username = :value AND Password = :password
type
僅包含任何預期值的時候,查詢才會正確執行。如果攻擊者提供 :value = :value OR :value
之類的 type 值,那麼查詢將會變更為::value = :value OR :value = :value AND Password = :password
:value = :value
會使 where 子句的評估永遠為 True,所以不論電子郵件擁有者為何,此查詢均會傳回 users
集合中儲存的所有項目。
...
// "type" parameter expected to be either: "Email" or "Username"
String type = request.getParameter("type")
String value = request.getParameter("value")
String password = request.getParameter("password")
DynamoDbClient ddb = DynamoDbClient.create();
HashMap<String, AttributeValue> attrValues = new HashMap<String,AttributeValue>();
attrValues.put(":value", AttributeValue.builder().s(value).build());
attrValues.put(":password", AttributeValue.builder().s(password).build());
ScanRequest queryReq = ScanRequest.builder()
.filterExpression(type + " = :value AND Password = :password")
.tableName("users")
.expressionAttributeValues(attrValues)
.build();
ScanResponse response = ddb.scan(queryReq);
...
Email = :value AND Password = :password
Username = :value AND Password = :password
type
僅包含任何預期值的時候,查詢才會正確執行。如果攻擊者提供 :value = :value OR :value
之類的 type 值,那麼查詢將會變更為::value = :value OR :value = :value AND Password = :password
:value = :value
會使 where 子句的評估永遠為 True,所以不論電子郵件擁有者為何,此查詢均會傳回 users
集合中儲存的所有項目。
...
String userName = User.Identity.Name;
String emailId = request["emailId"];
var coll = mongoClient.GetDatabase("MyDB").GetCollection<BsonDocument>("emails");
var docs = coll.Find(new BsonDocument("$where", "this.name == '" + name + "'")).ToList();
...
this.owner == "<userName>" && this.emailId == "<emailId>"
emailId
沒有包含單引號字元的時候,查詢才會正確執行。如果使用者名稱為 wiley
的攻擊者在 emailId
中輸入字串 123' || '4' != '5
,那麼查詢將變成以下內容:
this.owner == 'wiley' && this.emailId == '123' || '4' != '5'
|| '4' != '5'
會使 where 子句的評估永遠為 true
,所以不論電子郵件擁有者為何,此查詢均會傳回 emails
集合中儲存的所有項目。
...
String userName = ctx.getAuthenticatedUserName();
String emailId = request.getParameter("emailId")
MongoCollection<Document> col = mongoClient.getDatabase("MyDB").getCollection("emails");
BasicDBObject Query = new BasicDBObject();
Query.put("$where", "this.owner == \"" + userName + "\" && this.emailId == \"" + emailId + "\"");
FindIterable<Document> find= col.find(Query);
...
this.owner == "<userName>" && this.emailId == "<emailId>"
emailId
不包含雙引號字元的時候,查詢才會正確執行。 如果使用者名稱為 wiley
的攻擊者在 emailId
中輸入字串 123" || "4" != "5
,那麼查詢將變成以下內容:
this.owner == "wiley" && this.emailId == "123" || "4" != "5"
|| "4" != "5"
會使 where 子句的評估永遠為 True,所以不論電子郵件擁有者為何,此查詢會傳回 emails
集合中儲存的所有項目。
...
userName = req.field('userName')
emailId = req.field('emaiId')
results = db.emails.find({"$where", "this.owner == \"" + userName + "\" && this.emailId == \"" + emailId + "\""});
...
this.owner == "<userName>" && this.emailId == "<emailId>"
emailId
不包含雙引號字元的時候,查詢才會正確執行。 如果使用者名稱為 wiley
的攻擊者在 emailId
中輸入字串 123" || "4" != "5
,那麼查詢將變成以下內容:
this.owner == "wiley" && this.emailId == "123" || "4" != "5"
|| "4" != "5"
會使 where
子句的評估永遠為 True,所以不論電子郵件擁有者為何,此查詢會傳回 emails
集合中儲存的所有項目。NullException
。cmd
」的屬性。如果攻擊者可以控制程式環境,使「cmd
」變成未定義狀態,那麼程式會在嘗試呼叫 Trim()
方法時拋出一個 Null 指標異常。
string cmd = null;
...
cmd = Environment.GetEnvironmentVariable("cmd");
cmd = cmd.Trim();
null
之前先解除參照可能為 null
的指標,將會造成「解除參照之後檢查」的錯誤。當程式執行明確的 null
檢查,但仍繼續解除參照已知為 null
的指標時,將會造成「檢查後解除參照」的錯誤。這種類型的錯誤通常是打字錯誤或程式設計師的疏忽所造成。當程式明確的將某指標設定為 null
,卻在之後解除參考該指標,則會發生儲存後解除參照錯誤。這種錯誤通常是由於程式設計師在宣告變數時將變數初始化為 null
所致。ptr
不是 NULL
。當程式設計師取消參照指標時,這個假設就變得清楚。當程式設計師檢查 ptr
為 NULL
時,這個假設其實就出現其矛盾之處。若在 if
指令中檢查 ptr
時,其可為 NULL
,則解除參照時也可為 NULL
,並產生分段錯誤。範例 2:在以下程式碼中,程式設計師確定變數
ptr->field = val;
...
if (ptr != NULL) {
...
}
ptr
是 NULL
,並在之後以錯誤的方式解除參照。若在 if
陳述式中檢查 ptr
時,其非 NULL
,就會發生 null
解除參照,從而導致分段錯誤。範例 3:在以下程式碼中,程式設計師忘記了字串
if (ptr == null) {
ptr->field = val;
...
}
'\0'
實際上是 0 還是 NULL
,因此解除參照 Null 指標,並導致分段錯誤。範例 4:在以下程式碼中,程式設計師明確地將變數
if (ptr == '\0') {
*ptr = val;
...
}
ptr
設定為 NULL
。之後,程式設計師先解除參照 ptr
,再檢查物件是否為 null
值。
*ptr = NULL;
...
ptr->field = val;
...
}
NullPointerException
。cmd
」的屬性。如果攻擊者可以控制程式環境,使「cmd
」變成未定義狀態,那麼程式會在嘗試呼叫 trim()
方法時拋出一個 Null 指標異常。
String val = null;
...
cmd = System.getProperty("cmd");
if (cmd)
val = util.translateCommand(cmd);
...
cmd = val.trim();
clone()
方法應呼叫 super.clone()
來取得新的物件。clone()
方法的執行中,都應透過呼叫 super.clone()
來取得新物件。如果某個類別無法遵守這個慣例,那麼子類別的 clone()
方法將會回傳錯誤的物件類型。super.clone()
而產生的錯誤。由於類別的 Kibitzer
執行 clone()
方法,FancyKibitzer
類別的複製方法將會回傳 Kibitzer
類型的物件,而非 FancyKibitzer
類型。
public class Kibitzer implements Cloneable {
public Object clone() throws CloneNotSupportedException {
Object returnMe = new Kibitzer();
...
}
}
public class FancyKibitzer extends Kibitzer
implements Cloneable {
public Object clone() throws CloneNotSupportedException {
Object returnMe = super.clone();
...
}
}
equals()
和 hashCode()
。a.equals(b) == true
,那麼 a.hashCode() == b.hashCode()
。 equals()
,但是沒有替換 hashCode()
。
public class halfway() {
public boolean equals(Object obj) {
...
}
}
saveState()
和 restoreState()
。saveState(javax.faces.context.FacesContext)
及 restoreState(javax.faces.context.FacesContext, java.lang.Object)
,或者兩個方法都不實作。因為這兩個方法有緊密連結的關係,所以不允許將 saveState(javax.faces.context.FacesContext)
和 restoreState(javax.faces.context.FacesContext, java.lang.Object)
兩個方法置於繼承體系的不同層級中。saveState()
,但未定義 restoreState()
,所以不論延伸此類別的任何類別執行操作,它總是會出錯。
public class KibitzState implements StateHolder {
public Object saveState(FacesContext fc) {
...
}
}
SqlClientPermission
物件,其規定使用者可連接到資料庫的方式。在此範例中,程式把 false
作為第二個參數傳遞給構造函數,控制使用者是否可使用空白密碼進行連接。若傳送的參數值為 false,表示不允許密碼為空白。
...
SCP = new SqlClientPermission(pstate, false);
...
PermissionState
物件代替了所有傳遞至第二個參數的值,因此構造函數允許使用空白密碼進行資料庫連線,這與第二個引數互相矛盾。若要禁止使用空白密碼,程式應該把 PermissionState.None
傳遞給建構函數的第一個參數。因為其功能的不明確,SqlClientPermission
構造函數的雙參數版本已遭反對,改用單參數版本,單參數版本可提供與雙參數版本相同的功能,但是避免了誤譯的風險。getpw()
來驗證純文字密碼是否與使用者加密密碼相符。如果密碼有效,則函數將把 result
設為 1;如果無效,則將其設為 0。
...
getpw(uid, pwdline);
for (i=0; i<3; i++){
cryptpw=strtok(pwdline, ":");
pwdline=0;
}
result = strcmp(crypt(plainpw,cryptpw), cryptpw) == 0;
...
getpw(
) 函數會產生問題,因為這會導致傳遞至其第二個參數的緩衝區發生溢位。鑒於存在這一弱點,getpw()
已由 getpwuid()
取代,後者會執行與 getpw()
相同的查詢,但是會傳回指向靜態分配之結構的指標以降低風險。
...
String name = new String(nameBytes, highByte);
...
nameBytes
所呈現的字串而定。由於用於編碼字串的字元組的演變,所以不推薦使用此建構函式,取而代之的是新的構造函式。新的構造函式可接受作為名為 charset
的其中一個參數,用來編碼字元組以進行字元轉換。Digest::HMAC
stdlib,但由於在發行中意外涉及,因此在文件中明確不鼓勵使用。
require 'digest/hmac'
hmac = Digest::HMAC.new("foo", Digest::RMD160)
...
hmac.update(buf)
...
Digest::HMAC
類別時便會立即捨棄。由於實驗性和未正確測試的程式碼造成此要求無法如預期般運作,強烈勸阻使用此類別,尤其考慮到加密式功能涉及的關係 HMAC。checkCallingOrSelfPermission()
或 checkCallingOrSelfUriPermission()
函數會判定呼叫的程式是否有存取某些服務或特定 URI 的必要權限。但是,您應謹慎使用這些函數,因為他們可能在沒有適當權限的情況下取得您的應用程式權限,而授與惡意應用程式的存取權。
IPAddress hostIPAddress = IPAddress.Parse(RemoteIpAddress);
IPHostEntry hostInfo = Dns.GetHostByAddress(hostIPAddress);
if (hostInfo.HostName.EndsWith("trustme.com")) {
trusted = true;
}
getlogin()
函數很容易欺騙。請勿依賴其傳回的名稱。getlogin()
函數應該傳回包含目前已登入終端機的使用者名稱的字串,但是攻擊者可能讓 getlogin()
傳回登入該機器的任意使用者的名稱。請勿依賴 getlogin()
傳回的名稱來確定是否安全。getlogin()
來判定是否信任使用者。這很容易被推翻。
pwd = getpwnam(getlogin());
if (isTrustedGroup(pwd->pw_gid)) {
allow();
} else {
deny();
}
String ip = request.getRemoteAddr();
InetAddress addr = InetAddress.getByName(ip);
if (addr.getCanonicalHostName().endsWith("trustme.com")) {
trusted = true;
}
Boolean.getBoolean()
方法經常會與 Boolean.valueOf()
或 Boolean.parseBoolean()
方法呼叫混淆。Boolean.getBoolean()
經常被誤用,因為一般認為它會傳回由指定的 String 引數代表的布林值。但是,如 Javadoc Boolean.getBoolean(String)
方法中所述,「只有當引數命名的系統屬性存在且等於 String 'true'時傳回 true」("Returns true if and only if the system property named by the argument exists and is equal to the string 'true'.")。Boolean.valueOf(String)
或 Boolean.parseBoolean(String)
方法。Boolean.getBoolean(String)
不會轉譯 String 基本元。它只會轉譯系統屬性。
...
String isValid = "true";
if ( Boolean.getBoolean(isValid) ) {
System.out.println("TRUE");
}
else {
System.out.println("FALSE");
}
...