소프트웨어 보안은 보안 소프트웨어가 아닙니다. 여기서는 인증, 액세스 제어, 기밀성, 암호화, 권한 관리 등의 항목에 대해 설명합니다.
[AllowAnonymous]
속성을 사용하여 [Authorize]
속성이 부여한 권한 부여를 우회합니다.[Authorize]
속성을 클래스 또는 메서드에 추가하여 응용 프로그램 작업에 권한 부여가 필요하도록 만들 수 있습니다. 또한 [AllowAnonymous]
속성을 추가하여 응용 프로그램 클래스 또는 메서드의 지정된 권한 부여 요구 사항을 우회할 수 있습니다. 둘 다 지정하면 [AllowAnonymous]
속성이 우선적으로 적용되고 [Authorize]
속성을 우회합니다. 이로 인해 공격자가 민감한 데이터 및 작업에 임의로 익명으로 액세스할 수 있습니다.[Authorize]
속성을 재정의하는 클래스 수준의 [AllowAnonymous]
속성을 보여줍니다. secretAction()
메서드는 [Authorize]
속성이 있음에도 불구하고 권한 부여가 필요하지 않습니다.예제 2: 다음 예제는 하위 클래스의 메서드에 설정된
...
[AllowAnonymous]
public class Authorization_Test
{
[Authorize]
public IActionResult secretAction()
{
}
}
...
[Authorize]
속성을 재정의하는 슈퍼클래스 클래스 수준의 [AllowAnonymous]
속성을 보여줍니다. 상속된 클래스 Inherit_AA
의 [AllowAnonymous]
속성으로 인해 secretAction()
메서드는[Authorize]
속성을 지정함에도 불구하고 권한 부여가 필요하지 않습니다.예제 3: 다음은 상속이 있는 메서드 수준에서
...
[AllowAnonymous]
public abstract class Inherit_AA
{
}
public class Authorization_Test:Inherit_AA
{
[Authorize]
public IActionResult secretAction()
{
}
}
...
[Authorize]
속성을 재정의하는 [AllowAnonymous]
속성을 보여줍니다. 상속된 메서드 secretAction()
의 [AllowAnonymous]
속성으로 인해 secretAction()
메서드는[Authorize]
속성을 지정함에도 불구하고 권한 부여가 필요하지 않습니다.
...
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
매개 변수를 선택한다고 해도 공격자는 이를 public-read-write
로 설정하고 버킷에 대한 전체 익명 액세스 권한을 부여할 수 있습니다.
...
String selectedInvoice = request.getParameter("invoiceDate");
...
AmazonSimpleDBClient sdbc = new AmazonSimpleDBClient(appAWSCredentials);
GetAttributesResult sdbResult = sdbc.getAttributes(new GetAttributesRequest("invoices", selectedInvoice));
...
Example 1
의 코드는 현재 사용자의 송장 목록을 생성하지만 공격자는 이 동작을 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
id = this.getIntent().getExtras().getInt("id");
cursor = db.query(Uri.parse(invoices), columns, "id = ? ", {id}, null, null, null);
...
id
의 가능한 모든 값을 고려할 수 없다는 점입니다. 쿼리에서 현재 사용자의 송장 ID 목록을 생성하지만 공격자는 이 동작을 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.DirectoryEntry de
를 생성합니다.
...
de = new DirectoryEntry("LDAP://ad.example.com:389/ou=People,dc=example,dc=com");
...
de
에 대해 실행된 모든 LDAP 쿼리는 authentication 및 access control 없이 수행됩니다. 공격자는 디렉터리의 액세스 제어 메커니즘으로 보호되는 레코드에 대한 액세스를 얻기 위해 예기치 못한 방법으로 이러한 쿼리 중 하나를 조작할 수도 있습니다.ldap_simple_bind_s()
를 사용하여 LDAP 디렉터리에 익명으로 바인딩합니다.
...
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
...
}
...
ld
에 대해 실행된 모든 LDAP 쿼리는 authentication 및 access control 없이 수행됩니다. 공격자는 디렉터리의 액세스 제어 메커니즘으로 보호되는 레코드에 대한 액세스를 얻기 위해 예기치 못한 방법으로 이러한 쿼리 중 하나를 조작할 수도 있습니다.DirContext ctx
를 생성합니다.
...
env.put(Context.SECURITY_AUTHENTICATION, "none");
DirContext ctx = new InitialDirContext(env);
...
ctx
에 대해 실행된 모든 LDAP 쿼리는 authentication 및 access control 없이 수행됩니다. 공격자는 디렉터리의 액세스 제어 메커니즘으로 보호되는 레코드에 대한 액세스를 얻기 위해 예기치 못한 방법으로 이러한 쿼리 중 하나를 조작할 수도 있습니다.
...
$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
매개 변수에 공백을 제공하면 직원의 개인 정보 및 연락처 정보를 반환하기 전에 권한 부여 검사가 수행되지 않습니다.예제 2: 다음 코드에서는 지정된 blob 컨테이너와 해당 콘텐트를 삭제합니다.
...
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
과 Example 2
의 코드는 현재 사용자/프로그램에 속하는 지정된 큐/blob 컨테이너 및 해당 메시지/콘텐트를 삭제하지만 공격자는 해당 Azure 계정의 모든 큐/blob를 삭제할 수 있습니다. 이 예제의 코드는 사용자/프로그램에게 요청한 큐/blob를 지울 권한이 있는지를 확인하지 않으므로 현재 사용자/프로그램에 속하지 않는 큐/blob도 지웁니다.
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
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
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
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.inputID
값은 사전 정의된 목록에서 제공되며, 바인딩 변수는 SOQL/SOSL injection을 방지하는 데 도움이 됩니다.
...
result = [SELECT Name, Phone FROM Contact WHERE (IsDeleted = false AND Id=:inputID)];
...
inputID
의 값을 수정하지 못하도록 방지하기에는 불충분하다는 점입니다. 공격자가 인터페이스를 우회하고 다른 값으로 요청을 전송할 수 있는 경우 공격자는 다른 연락처 정보에 액세스할 수 있습니다. 이 예제의 코드는 사용자가 요청된 연락처에 액세스할 수 있는 권한이 있는지 확인하지 않으므로, 사용자가 볼 권한이 없는 경우에도 모든 연락처를 표시합니다.
...
int16 id = System.Convert.ToInt16(invoiceID.Text);
var invoice = OrderSystem.getInvoices()
.Where(new Invoice { invoiceID = id });
...
id
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
CMyRecordset rs(&dbms);
rs.PrepareSQL("SELECT * FROM invoices WHERE id = ?");
rs.SetParam_int(0,atoi(r.Lookup("invoiceID").c_str()));
rs.SafeExecuteSQL();
...
id
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
ACCEPT ID.
EXEC SQL
DECLARE C1 CURSOR FOR
SELECT INVNO, INVDATE, INVTOTAL
FROM INVOICES
WHERE INVOICEID = :ID
END-EXEC.
...
ID
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.deleteDatabase
메서드를 실행하면 공격자가 모든 데이터베이스를 삭제할 수 있게 됩니다.
...
id := request.FormValue("invoiceID")
query := "SELECT * FROM invoices WHERE id = ?";
rows, err := db.Query(query, id)
...
id
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
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
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.Example 1
을 Android 플랫폼에 맞게 조정합니다.
...
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
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
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
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
$id = $_POST['id'];
$query = "SELECT * FROM invoices WHERE id = ?";
$stmt = $mysqli->prepare($query);
$stmt->bind_param('ss',$id);
$stmt->execute();
...
id
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
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
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
id = request.POST['id']
c = db.cursor()
stmt = c.execute("SELECT * FROM invoices WHERE id = %s", (id,))
...
id
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
id = req['invoiceID'].respond_to(:to_int)
query = "SELECT * FROM invoices WHERE id=?"
stmt = conn.prepare(query)
stmt.execute(id)
...
id
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
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
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
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
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
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
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.
...
ACCEPT ID.
EXEC DLI
GU
SEGMENT(INVOICES)
WHERE (INVOICEID = ID)
END-EXEC.
...
ID
의 가능한 모든 값을 고려할 수 없다는 점입니다. 인터페이스에서 현재 사용자의 송장 ID 목록을 생성하더라도 공격자는 이 인터페이스를 무시하고 원하는 송장을 요청할 수 있습니다. 이 예제의 코드가 사용자가 요청한 송장에 접근할 수 있는 권한이 있는지 확인하지 않기 때문에 현재 사용자의 송장이 아닌 송장도 모두 표시합니다.aspnet:UseLegacyFormsAuthenticationTicketCompatibility
설정을 사용하여 검증되지 않은 입력이 기본 API로 전달되도록 허용하고 공격자가 인증을 우회할 수 있도록 이 기능을 수정할 수 있다는 것입니다. 이 취약점 악용에 성공한 공격자는 알려진 사용자 이름에 대해 암호 없이 ASP.NET 양식 인증을 우회할 수 있습니다. 그런 다음 사이트에서 임의의 명령을 실행하는 것을 포함하여 피해 사용자의 컨텍스트에서 모든 작업을 수행할 수 있습니다.aspnet:UseLegacyFormsAuthenticationTicketCompatibility
이 true
로 설정됩니다.
...
<appSettings>
<add key="aspnet:UseLegacyFormsAuthenticationTicketCompatibility" value="true" />
</appSettings>
...
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
의 다른 값을 제공할 경우 발생될 일에 대해 고려하지 못했다는 점입니다. 인터페이스에서 현재 사용자의 직원 ID를 자동으로 제공하지만 공격자는 악의적인 요청의 일부로 다른 값을 제공할 수 있습니다. 이 예제의 코드가 익명의 바인딩에서 쿼리를 실행하므로 현재 인증된 사용자의 ID와 관계 없이 올바른 직원 ID에 대한 디렉터리 항목을 반환할 것입니다.
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
의 다른 값을 제공할 경우 발생될 일에 대해 고려하지 못했다는 점입니다. 이 예제의 코드가 익명의 바인딩에서 쿼리를 실행하므로 현재 인증된 사용자의 ID와 관계 없이 올바른 직원 ID에 대한 디렉터리 항목을 반환할 것입니다.
...
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
의 다른 값을 제공할 경우 발생될 일에 대해 고려하지 못했다는 점입니다. 인터페이스에서 현재 사용자의 직원 ID를 자동으로 제공하지만 공격자는 악의적인 요청의 일부로 다른 값을 제공할 수 있습니다. 이 예제의 코드가 익명의 바인딩에서 쿼리를 실행하므로 현재 인증된 사용자의 ID와 관계 없이 올바른 직원 ID에 대한 디렉터리 항목을 반환할 것입니다.
...
CALL TRANSACTION 'SA38'.
...
MQOD-ALTERNATEUSERID
및 MQOD-ALTERNATESECURITYID
필드를 제어하는 데 사용합니다.
...
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
문을 추가 FOR USER
와 함께 사용AUTHORITY_CHECK
함수 모듈 호출SU_RAUTH_CHECK_FOR_USER
함수 모듈 호출
...
AUTHORITY-CHECK OBJECT 'S_TCODE' FOR USER v_user
ID 'TCD' FIELD 'SA38'.
IF sy-subrc = 0.
CALL TRANSACTION 'SA38'.
ELSE.
...
with sharing
: 사용자 공유 규칙이 적용됩니다.without sharing
: 공유 규칙이 적용되지 않습니다.inherited sharing
: 호출 클래스의 공유 규칙이 적용됩니다. 호출 클래스가 공유 키워드를 지정하지 않거나 클래스 자체가 Visualforce 컨트롤러와 같은 진입점인 경우에는 사용자 공유 규칙이 기본적으로 적용됩니다.
public class TestClass1 {
public List<Contact> getAllTheSecrets() {
return Database.query('SELECT Name FROM Contact');
}
}
public without sharing class TestClass2 {
public List<Contact> getAllTheSecrets() {
return Database.query('SELECT Name FROM Contact');
}
}
public inherited sharing class TestClass3 {
public List<Contact> getAllTheSecrets() {
return Database.query('SELECT Name FROM Contact');
}
}
TestClass1
및 TestClass2
가 안전하지 않은 이유는 사용자 공유 규칙을 적용하지 않고도 레코드를 검색할 수 있기 때문입니다.TestClass3
의 경우에는 기본적으로 공유 규칙을 적용하므로 더 안전합니다. 그러나 without sharing
을 명시적으로 선언하는 클래스에서 getAllTheSecrets()
함수를 호출하는 경우에는 여전히 무단 액세스 권한을 부여할 수 있습니다.<security constraint>
요소는 프로그램에 RBAC(Role-Based Access Control)가 사용되고 있지 않음을 암시합니다. RBAC는 보안 웹 응용 프로그램에서 민감한 작업의 보호를 위해 널리 용인되는 모범 사례입니다. 민감한 작업 또는 데이터에 대한 액세스를 제공하는 응용 프로그램의 경우 권한이 없는 사용자의 액세스를 차단하는 충분한 제어가 없을 수 있습니다. 또한 <url-pattern>
에 와일드카드(*)가 있는 경우 패턴이 지나치게 광범위하다는 표시일 수 있습니다.
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
\A/secure/.*\Z=REQUIRES_SECURE_CHANNEL
\A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL
\A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL
\A.*\Z=REQUIRES_INSECURE_CHANNEL
</value>
</property>