Software security is not security software. Here we're concerned with topics like authentication, access control, confidentiality, cryptography, and privilege management.
[Authorize]
attribute with the use of an [AllowAnonymous]
attribute at the class or method level.[Authorize]
attribute to a class or a method. Additionally, the specified authorization requirement of an application class or method can be bypassed by adding the [AllowAnonymous]
attribute. When both are specified, the [AllowAnonymous]
attribute takes precedence and bypasses the [Authorize]
attribute. This can result in the arbitrary and anonymous access of sensitive data and actions by an attacker.[AllowAnonymous]
attribute at the class level overriding an [Authorize]
attribute set on the method. The secretAction()
method does not require authorization despite having the [Authorize]
attribute.Example 2: The following example shows the
...
[AllowAnonymous]
public class Authorization_Test
{
[Authorize]
public IActionResult secretAction()
{
}
}
...
[AllowAnonymous]
attribute at the class level of a superclass overriding an [Authorize]
attribute set on the method of a subclass. Due to the inherited class Inherit_AA
having the [AllowAnonymous]
attribute, the secretAction()
method does not require authorization despite specifying the [Authorize]
attribute.Example 3: The following shows the
...
[AllowAnonymous]
public abstract class Inherit_AA
{
}
public class Authorization_Test:Inherit_AA
{
[Authorize]
public IActionResult secretAction()
{
}
}
...
[AllowAnonymous]
attribute overriding an [Authorize]
attribute at the method level with inheritance. Due to the inherited method secretAction()
having the [AllowAnonymous]
attribute, the secretAction()
method does not require authorization despite specifying the [Authorize]
attribute on the overriding method.
...
public abstract class Inherit_AA
{
[AllowAnonymous]
public abstract IActionResult secretAction()
{
}
}
public class Authorization_Test:Inherit_AA
{
[Authorize]
public override IActionResult secretAction()
{
}
}
...
<apex:page controller="accessControl">
<apex:pageBlock >
<apex:pageBlockSection >
<apex:outputText value="Survey Name: "/>
<apex:inputText value="{!surveyName}"/>
</apex:pageBlockSection>
<apex:pageBlockSection >
<apex:outputText value="New Name: "/>
<apex:inputText value="{!newSurveyName}"/>
</apex:pageBlockSection>
<apex:pageBlockSection >
<apex:commandButton value="Update" action="{!updateName}"/>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:page>
public String surveyName { get; set; }
public String newSurveyName { get; set; }
public PageReference updateName() {
Survey__c s = [SELECT Name FROM Survey__c WHERE Name=:surveyName];
s.Name = newSurveyName;
update s;
PageReference page = ApexPages.currentPage();
page.setRedirect(true);
return page;
}
String canned_acl = request.getParameter("acl");
CreateBucketRequest createBucketRequest = CreateBucketRequest.builder()
.bucket("foo")
.acl(canned_acl)
.createBucketConfiguration(CreateBucketConfiguration.builder().locationConstraint(region.id()).build())
.build();
acl
parameter to be selected from a limited set, an attacker can set it to public-read-write
and grant full anonymous access to the bucket.
...
String selectedInvoice = request.getParameter("invoiceDate");
...
AmazonSimpleDBClient sdbc = new AmazonSimpleDBClient(appAWSCredentials);
GetAttributesResult sdbResult = sdbc.getAttributes(new GetAttributesRequest("invoices", selectedInvoice));
...
Example 1
generates a list of invoices that belong to the current user, an attacker might bypass this behavior to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
id = this.getIntent().getExtras().getInt("id");
cursor = db.query(Uri.parse(invoices), columns, "id = ? ", {id}, null, null, null);
...
id
. Although the query generates a list of invoice identifiers that belong to the current user, an attacker might bypass this behavior to request any desired invoice. Because the code in this example does not ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.DirectoryEntry de
using an anonymous bind.
...
de = new DirectoryEntry("LDAP://ad.example.com:389/ou=People,dc=example,dc=com");
...
de
will be performed without authentication and access control. An attacker may be able to manipulate one of these queries in an unexpected way to gain access to records that would otherwise be protected by the directory's access control mechanism.ldap_simple_bind_s()
to bind anonymously to an LDAP directory.
...
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
...
}
...
ld
will be performed without authentication and access control. An attacker may be able to manipulate one of these queries in an unexpected way to gain access to records that would otherwise be protected by the directory's access control mechanism.DirContext ctx
using an anonymous bind.
...
env.put(Context.SECURITY_AUTHENTICATION, "none");
DirContext ctx = new InitialDirContext(env);
...
ctx
will be performed without authentication and access control. An attacker may be able to manipulate one of these queries in an unexpected way to gain access to records that would otherwise be protected by the directory's access control mechanism.
...
$ldapbind = ldap_bind ($ldap, $dn, $password = "" );
...
...
PARAMETERS: p_xfeld TYPE xfeld.
...
CALL FUNCTION 'BAPI_EMPLOYEE_GETDATA'
EXPORTING
employee_id = emp_id
authority_check = p_xfeld
IMPORTING
return = ret
TABLES
org_assignment = org_data
personal_data = pers_data
internal_control = con_data
communication = comm_data
archivelink = arlink.
...
p_xfeld
, no authorization checks are performed before returning an employee's personal and contact information.Example 2: The following code deletes the given blob container and its contents.
...
var queueName = queryStringData['name'];
var queueSvc;
queueSvc = azureStorage.createQueueService();
...
queueSvc.deleteQueue(queueName, option, function(error, response){
if(!error){
// all the messages has been deleted
}
});
...
...
var containerName = queryStringData['name'];
var blobSvc;
blobSvc = azureStorage.createBlobService();
...
blobSvc.deleteContainer(containerName, function (error, response) {
if (!error) {
// all the content in the given container has been deleted
}
});
...
Example 1
and Example 2
delete the given queue/blob container and its messages/contents that belong to the current user/program, an attacker may delete any queue/blob for that Azure account. Because the code in this example does not check to ensure that the user/program has permission to clear the requested queue/blob, it will clear queue/blob, even if it does not belong to the current user/program.
public boolean isTrusted(String paramString) {
if (this._applicationContext.getPackageName().equalsIgnoreCase(paramString)) {
return true;
}
DATA: id TYPE i.
...
id = request->get_form_field( 'invoiceID' ).
CONCATENATE `INVOICEID = '` id `'` INTO cl_where.
SELECT *
FROM invoices
INTO CORRESPONDING FIELDS OF TABLE itab_invoices
WHERE (cl_where).
ENDSELECT.
...
ID
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var id:int = int(Number(params["invoiceID"]));
var query:String = "SELECT * FROM invoices WHERE id = :id";
stmt.sqlConnection = conn;
stmt.text = query;
stmt.parameters[":id"] = id;
stmt.execute();
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.inputID
value is originated from a pre-defined list, and a bind variable helps to prevent SOQL/SOSL injection.
...
result = [SELECT Name, Phone FROM Contact WHERE (IsDeleted = false AND Id=:inputID)];
...
inputID
. If the attacker is able to bypass the interface and send a request with a different value he will have access to other contact information. Since the code in this example does not check to ensure that the user has permission to access the requested contact, it will display any contact, even if the user is not authorized to see it.
...
int16 id = System.Convert.ToInt16(invoiceID.Text);
var invoice = OrderSystem.getInvoices()
.Where(new Invoice { invoiceID = id });
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
CMyRecordset rs(&dbms);
rs.PrepareSQL("SELECT * FROM invoices WHERE id = ?");
rs.SetParam_int(0,atoi(r.Lookup("invoiceID").c_str()));
rs.SafeExecuteSQL();
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
ACCEPT ID.
EXEC SQL
DECLARE C1 CURSOR FOR
SELECT INVNO, INVDATE, INVTOTAL
FROM INVOICES
WHERE INVOICEID = :ID
END-EXEC.
...
ID
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.deleteDatabase
method that contains a user-controlled database name can allow an attacker to delete any database.
...
id := request.FormValue("invoiceID")
query := "SELECT * FROM invoices WHERE id = ?";
rows, err := db.Query(query, id)
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
id = Integer.decode(request.getParameter("invoiceID"));
String query = "SELECT * FROM invoices WHERE id = ?";
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setInt(1, id);
ResultSet results = stmt.execute();
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.Example 1
to the Android platform.
...
String id = this.getIntent().getExtras().getString("invoiceID");
String query = "SELECT * FROM invoices WHERE id = ?";
SQLiteDatabase db = this.openOrCreateDatabase("DB", MODE_PRIVATE, null);
Cursor c = db.rawQuery(query, new Object[]{id});
...
...
var id = document.form.invoiceID.value;
var query = "SELECT * FROM invoices WHERE id = ?";
db.transaction(function (tx) {
tx.executeSql(query,[id]);
}
)
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:@"Invoices" inManagedObjectContext:context];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:entityDesc];
NSPredicate *pred = [NSPredicate predicateWithFormat:@"(id = %@)", invoiceId.text];
[request setPredicate:pred];
NSManagedObject *matches = nil;
NSError *error;
NSArray *objects = [context executeFetchRequest:request error:&error];
if ([objects count] == 0) {
status.text = @"No records found.";
} else {
matches = [objects objectAtIndex:0];
invoiceReferenceNumber.text = [matches valueForKey:@"invRefNum"];
orderNumber.text = [matches valueForKey:@"orderNumber"];
status.text = [NSString stringWithFormat:@"%d records found", [objects count]];
}
[request release];
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
$id = $_POST['id'];
$query = "SELECT * FROM invoices WHERE id = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('ss',$id);
$stmt->execute();
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
procedure get_item (
itm_cv IN OUT ItmCurTyp,
id in varchar2)
is
open itm_cv for ' SELECT * FROM items WHERE ' ||
'invoiceID = :invid' ||
using id;
end get_item;
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
id = request.POST['id']
c = db.cursor()
stmt = c.execute("SELECT * FROM invoices WHERE id = %s", (id,))
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
id = req['invoiceID'].respond_to(:to_int)
query = "SELECT * FROM invoices WHERE id=?"
stmt = conn.prepare(query)
stmt.execute(id)
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
def searchInvoice(value:String) = Action.async { implicit request =>
val result: Future[Seq[Invoice]] = db.run {
sql"select * from invoices where id=$value".as[Invoice]
}
...
}
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
let fetchRequest = NSFetchRequest()
let entity = NSEntityDescription.entityForName("Invoices", inManagedObjectContext: managedContext)
fetchRequest.entity = entity
let pred : NSPredicate = NSPredicate(format:"(id = %@)", invoiceId.text)
fetchRequest.setPredicate = pred
do {
let results = try managedContext.executeFetchRequest(fetchRequest)
let result : NSManagedObject = results.first!
invoiceReferenceNumber.text = result.valueForKey("invRefNum")
orderNumber.text = result.valueForKey("orderNumber")
status.text = "\(results.count) records found"
} catch let error as NSError {
print("Error \(error)")
}
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
id = Request.Form("invoiceID")
strSQL = "SELECT * FROM invoices WHERE id = ?"
objADOCommand.CommandText = strSQL
objADOCommand.CommandType = adCmdText
set objADOParameter = objADOCommand.CreateParameter("id" , adString, adParamInput, 0, 0)
objADOCommand.Parameters("id") = id
...
id
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.
...
ACCEPT ID.
EXEC DLI
GU
SEGMENT(INVOICES)
WHERE (INVOICEID = ID)
END-EXEC.
...
ID
. Although the interface generates a list of invoice identifiers that belong to the current user, an attacker might bypass this interface to request any desired invoice. Because the code in this example does not check to ensure that the user has permission to access the requested invoice, it will display any invoice, even if it does not belong to the current user.aspnet:UseLegacyFormsAuthenticationTicketCompatibility
setting to allow unvalidated input to be passed to the native APIs and may lead to an attacker being able to bypass authentication. An attacker who successfully exploites this vulnerability would be able to bypass ASP.NET forms authentication for any known username without its password. The attacker could then take any action in the context of the victim user, including executing arbitrary commands on the site.aspnet:UseLegacyFormsAuthenticationTicketCompatibility
is set to true
.
...
<appSettings>
<add key="aspnet:UseLegacyFormsAuthenticationTicketCompatibility" value="true" />
</appSettings>
...
Metadata
object is being accepted despite failing validation.Metadata
class is often used to house header data for an underlying protocol used by Google Remote Procedure Call (gRPC). When implementing the io.grpc.ServerInterceptor
class, Metadata
object should be validated and return error if exception is thrown.Metadata
object which is passing to the next io.grpc.ServerCallHandler
object after catching exception:
class PotentialAuthByPassInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata metadata, ServerCallHandler<ReqT, RespT> next) {
try {
customValidate(metadata);
} catch (RuntimeException e) {
return next.startCall(call, metadata);
}
...
return Contexts.interceptCall(Context.current(), call, metadata, next);
}
}
static string AllowlistVerify(string name) {
Regex pattern = new Regex(@"^[a-zA-Z\-\.']+$");
if (pattern.IsMatch(name)) {
return name;
}
return null;
}
...
string verifiedName = AllowlistVerify(managerName.Text.trim());
if(verifiedName != null) {
DirectorySearcher src = new DirectorySearcher("(manager=" + verifiedName + ")");
src.SearchRoot = de;
src.SearchScope = SearchScope.Subtree;
foreach(SearchResult res in src.FindAll()) {
...
}
}
empName
. Although the interface automatically submits the employee ID of the current user, an attacker could submit an alternative value as part of a malicious request. Because the code in this example executes the query under an anonymous bind, it will return the directory entry for any valid employee ID, regardless of the identity of the current authenticated user.
char* allowlist_verify(char* name) {
const char *error;
int errOffset;
char* regex = "^[a-zA-Z\\-\\.']+$";
pcre* re = pcre_compile(regex, 0, &err, &errOffset, NULL);
int rc = pcre_exec(re, NULL, name, strlen(name), 0, 0, NULL, 0);
if (rc == 1)
return name;
return NULL;
}
...
fgets(managerName, sizeof(managerName), socket);
char* verified_name = allowlist_verify(managerName);
if(verified_name != NULL) {
snprintf(filter, sizeof(filter), "(manager=%s)", verified_name);
if ( ( rc = ldap_search_ext_s( ld, FIND_DN, LDAP_SCOPE_BASE,
filter, NULL, 0, NULL, NULL, LDAP_NO_LIMIT,
LDAP_NO_LIMIT, &result ) ) == LDAP_SUCCESS ) {
...
}
}
username
. Because the code in this example executes the query under an anonymous bind, it will return the directory entry for any valid employee ID, regardless of the identity of the current authenticated user.
...
env.put(Context.SECURITY_AUTHENTICATION, "none");
DirContext ctx = new InitialDirContext(env);
String empID = request.getParameter("empID");
try
{
int id = Integer.parseInt(empID);
BasicAttribute attr = new BasicAttribute("empID", empID);
NamingEnumeration employee =
ctx.search("ou=People,dc=example,dc=com",attr);
...
empID
. Although the interface automatically submits the employee ID of the current user, an attacker could submit an alternative value as part of a malicious request. Because the code in this example executes the query under an anonymous bind, it will return the directory entry for any valid employee ID, regardless of the identity of the current authenticated user.
...
CALL TRANSACTION 'SA38'.
...
MQOD-ALTERNATEUSERID
and MQOD-ALTERNATESECURITYID
fields of the MQ object descriptor.
...
10 MQOD.
** Alternate user identifier
15 MQOD-ALTERNATEUSERID PIC X(12).
** Alternate security identifier
15 MQOD-ALTERNATESECURITYID PIC X(40).
...
...
ACCEPT MQOD-ALTERNATEUSERID.
ACCEPT MQOD-ALTERNATESECURITYID.
CALL 'MQOPEN' USING HCONN, MQOD, OPTS, HOBJ, COMPOCODE REASON.
...
AUTHORITY-CHECK
is used together with the addition FOR USER
AUTHORITY_CHECK
is invoked with the specified userSU_RAUTH_CHECK_FOR_USER
is invoked with the specified user
...
AUTHORITY-CHECK OBJECT 'S_TCODE' FOR USER v_user
ID 'TCD' FIELD 'SA38'.
IF sy-subrc = 0.
CALL TRANSACTION 'SA38'.
ELSE.
...
$admintest = 0;
if(isset($admin)) {
if(!IsSet($mainfile)) { include("mainfile.php3"); }
$admin = base64_decode($admin);
$admin = explode(":", $admin);
$aid = "$admin[0]";
$pwd = "$admin[1]";
dbconnect();
$result=mysql_query("select pwd from authors where aid='$aid'");
if(!$result) {
echo "Selection from database failed!";
exit;
} else {
list($pass)=mysql_fetch_row($result);
if($pass == $pwd) {
$admintest = 1;
}
}
}
$admin
value for access control checks. Any variables, either from cookies or forms (GET/POST) is automatically made global to the script by PHP. An attacker can manipulate the value of the admin
variable by passing the desired value using a request parameter. If $pwd
(an element of that "scrambled" $admin
) does not match the value that corresponds to the fetched row, the false authentication ($admintest
= 0) is returned, otherwise we'll be able to access any function in admin.php3.$pass == $pwd
. The $pass
value returned from mysql_fetch_row()
can be anything, or can be FALSE
if there are no more rows. The attacker in this case can exploit the mismatch in the datatype to equalize $pwd
(string-type) and $pass
(logical-type). The expression "if($pass == $pwd)"
only compares values, NOT the type. As a result, setting $pwd = ""
(null) is EQUAL
(though not identical) to the given FALSE
value of $pass
.$pass
to FALSE
, the attacker only needs to set $aid
to a string value that does not exist in the database. This results in the mysql_query()
call to return TRUE
and the mysql_fetch_row()
call to return FALSE
.
$aid = "blabla"; $pwd = "";
base64_encode("$aid:$pwd")
in the admin
request parameter.