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 Web Form 应用程序中,将
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
) 从 Web 表单进行访问,该表单要求用户通过提供其姓名和密码注册帐户。
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
dereference。
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
太大,还是因为在同一时刻处理的请求太多。或者是由于已累计超时的 memory leak 引起的。如果不对错误进行处理,就不会知道是什么原因。null
。compareTo()
之前,不会检查 getParameter()
返回的字符串是否为 null
,从而可能会造成 null
dereference。例 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
等类型值,则该查询会变成::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
等类型值,则该查询会变成::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
之前间接引用该指针,则会发生 check-after-dereference 错误。如果程序明确检查过 null
,并确定该指针为 null
,但仍继续间接引用该指针,则会出现 dereference-after-check 错误。此类错误通常是由于错别字或程序员疏忽造成的。如果程序明确将指针设置为 null
,但稍后却间接引用该指针,则将出现 dereference-after-store 错误。此错误通常是因为程序员在声明变量时将该变量初始化为 null
所致。ptr
不是 NULL
。当程序员间接引用该指针时,这个假设就会清晰的体现出来。当程序员检查 ptr
是否为 NULL
时,就会与该假设发生矛盾。当在 if
语句中检查时,如果 ptr
可以为 NULL
,则在其间接引用时也将为 NULL
,并引起 segmentation fault。示例 2:在下列代码中,程序员会确认变量
ptr->field = val;
...
if (ptr != NULL) {
...
}
ptr
为 NULL
,然后错误地对其进行间接引用。如果在 if
语句中检查 ptr
时其为 NULL
,则会发生 null
dereference,从而导致分段故障。示例 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()
而产生的 bug。由于 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()
来返回指定字符串变量表示的布尔值,因而导致此方法的调用使用不当。但是,正如 Javadoc Boolean.getBoolean(String)
方法所说,“当且仅当该参数表示的系统属性存在且等于字符串 'true' 时,才会返回 true。”Boolean.valueOf(String)
或 Boolean.parseBoolean(String)
方法。Boolean.getBoolean(String)
不会对基元型字符串进行转换。它只能对系统属性进行转换。
...
String isValid = "true";
if ( Boolean.getBoolean(isValid) ) {
System.out.println("TRUE");
}
else {
System.out.println("FALSE");
}
...