API는 호출자와 피호출자 간의 계약입니다. 가장 흔한 형태의 API 오용은 호출자가 이 계약에서 자신의 몫을 이행하지 못하기 때문에 발생합니다. 예를 들어, 프로그램이 chroot()를 호출한 후 chdir()을 호출하지 못하면 활성 루트 디렉터리를 안전하게 변경하는 방법을 지정하는 계약을 위반하는 것입니다. 라이브러리 오용의 또 다른 좋은 예는 피호출자가 호출자에게 신뢰할 만한 DNS 정보를 반환할 것으로 예상하는 것입니다. 이 경우, 호출자는 자신의 행동에 대해 특정한 가정을 함으로써(반환 값이 인증 목적으로 사용될 것으로 예상) 피호출자 API를 오용합니다. 다른 쪽에서 호출자-피호출자 계약을 위반할 수도 있습니다. 예를 들어, 코더가 하위 클래스 SecureRandom을 지정하고 임의 값이 아닌 값을 반환하는 경우 계약을 위반하는 것입니다.
unsecure
속성은 클라이언트에서 그 값이 설정될 수 있는 속성의 목록을 지정합니다.unsecure
속성은 그러한 목록을 지정할 수 있습니다.unsecure
속성 내에 나타날 수 있는 유일한 속성은 disabled
이며, 이는 활성화되는 구성 요소와 그렇지 않은 구성 요소를 클라이언트가 정의하도록 허용합니다. 서버에서만 설정할 수 있는 속성의 값을 클라이언트가 제어하도록 하는 것은 좋은 방법이 아닙니다.unsecure
속성을 사용하는 inputText
구성 요소를 보여줍니다.
...
<af:inputText id="pwdBox"
label="#{resources.PWD}"
value=""#{userBean.password}
unsecure="disabled"
secret="true"
required="true"/>
...
file://
프로토콜에 대해 쿠키를 사용하도록 허용하며, 이로 인해 예기치 않은 보안 영향이 발생할 수 있습니다.file://
을 비롯해, HTTP 이외의 프로토콜에서 작동한다고 기대할 합리적인 이유가 없습니다. 어떤 동작이 수행될지, 어떤 보안 분류 규칙이 적용될지가 분명하지 않습니다. 예를 들어 인터넷 공유에서 로컬 디스크로 HTML 파일을 다운로드해야 한다면 HTML 코드처럼 동일한 쿠키가 로컬에 설치됩니까?UseCookiePolicy()
메서드는 쿠키 정책 미들웨어를 미들웨어 파이프라인에 추가하여 사용자 지정 쿠키 정책을 허용합니다. 표시된 대로 잘못된 순서로 지정하면 프로그래머가 지정한 모든 쿠키 정책이 무시됩니다.
...
var builder = WebApplication.CreateBuilder(...);
var app = builder.Build(...);
app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
...
}
app.UseCookiePolicy();
...
UseHttpsRedirection()
메서드는 안전하지 않은 HTTP 요청을 안전한 HTTPS 요청으로 리디렉션할 수 있도록 미들웨어 파이프라인에 HTTPS 리디렉션 미들웨어를 추가합니다. 표시된 대로 잘못된 순서로 지정하면 리디렉션 전에 나열된 미들웨어를 통해 요청을 처리하기 전에 의미 있는 HTTPS 리디렉션이 발생하지 않습니다. 이렇게 하면 안전한 HTTPS 연결로 리디렉션되기 전에 응용 프로그램에서 HTTP 요청을 처리할 수 있습니다.
...
var builder = WebApplication.CreateBuilder(...);
var app = builder.Build(...);
app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
...
}
app.UseHttpsRedirection();
...
UseHttpLogging()
메서드는 미들웨어 구성 요소가 로깅할 수 있도록 미들웨어 파이프라인에 HTTP 로깅 미들웨어를 추가합니다. 표시된 대로 잘못된 순서로 지정하면 UseHttpLogging()
호출 전에 파이프라인에 추가된 미들웨어는 로깅되지 않습니다.예제 2:
...
var builder = WebApplication.CreateBuilder(...);
var app = builder.Build(...);
app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
...
}
app.UseHttpLogging();
...
UseWC3Logging()
메서드는 미들웨어 구성 요소가 로깅할 수 있도록 미들웨어 파이프라인에 W3C 로깅 미들웨어를 추가합니다. 표시된 대로 잘못된 순서로 지정하면 UseWC3Logging()
호출 전에 파이프라인에 추가된 미들웨어는 로깅되지 않습니다.
...
var builder = WebApplication.CreateBuilder(...);
var app = builder.Build(...);
app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
...
}
app.UseWC3Logging();
...
public ActionResult UpdateWidget(Model model)
{
// ... controller logic
}
[Required]
속성으로 표시되는 필수 속성과 [Required]
속성으로 표시되지 않는 옵션 속성이 모두 포함된 모델 클래스를 사용하는 경우, 공격자가 필요한 것보다 많은 데이터가 포함된 요청을 전달하면 문제가 발생할 수 있습니다.[Required]
가 지정된 속성과 [Required]
가 지정되지 않은 속성이 포함된 가능 모델 클래스를 정의합니다.
public class MyModel
{
[Required]
public String UserName { get; set; }
[Required]
public String Password { get; set; }
public Boolean IsAdmin { get; set; }
}
[Required]
속성으로 표시됨)이 포함된 모델 클래스를 사용하는 경우, 공격자가 필요한 것보다 적은 데이터가 포함된 요청을 전달하면 문제가 발생할 수 있습니다.[Required]
확인 속성이 충족됩니다. 따라서 응용 프로그램이 예기치 않게 동작할 수 있습니다.
public enum ArgumentOptions
{
OptionA = 1,
OptionB = 2
}
public class Model
{
[Required]
public String Argument { get; set; }
[Required]
public ArgumentOptions Rounding { get; set; }
}
[Required]
속성이 없는 속성이 있는 경우에 공격자가 해당 하위 모델을 전달하지 않으면 상위 모델에는 null
값이 지정되고 하위 모델의 필수 필드가 모델 확인을 통해 어설션되지 않습니다. 이는 under-posting 공격의 한 형태입니다.
public class ChildModel
{
public ChildModel()
{
}
[Required]
public String RequiredProperty { get; set; }
}
public class ParentModel
{
public ParentModel()
{
}
public ChildModel Child { get; set; }
}
ParentModel.Child
속성의 값을 전달하지 않으면 ChildModel.RequiredProperty
속성에 [Required]
가 지정되며, 이 값은 어설션되지 않습니다. 따라서 예기치 않은 부적절한 결과가 발생할 수 있습니다.
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:nil
reply:^(BOOL success, NSError *error) {
if (success) {
NSLog(@"Auth was OK");
}
}];
context.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "", reply: { (success, error) -> Void in
if (success) {
print("Auth was OK");
}
else {
print("Error received: %d", error!);
}
})
SHARED
로 지정합니다.
results = query.execute(Database.SHARED);
results = query.execute(); //missing query mode
GC.Collect()
를 삽입하면 문제가 사라지는 경우가 있다는 것입니다.GC.Collect()
호출은 바르지 못한 방법입니다. 실제로 GC.Collect()
를 너무 자주 호출하면 성능 문제가 생길 수 있습니다.System.gc()
를 삽입하면 문제가 사라지는 경우가 있다는 것입니다.System.gc()
호출은 바르지 못한 방법입니다. 실제로 System.gc()
를 너무 자주 호출하면 성능 문제가 생길 수 있습니다.Equals()
는 Equals()
를 구현하지 않는 개체에서 호출됩니다.Equals()
를 명시적으로 구현하지 않는 클래스(또는 임의의 수퍼 클래스/인터페이스)에서 Equals()
를 호출하면 System.Object
에서 상속된 Equals()
메서드를 호출하게 됩니다. 개체 멤버 필드 또는 기타 속성을 비교하는 대신, Object.Equals()
는 동일한지 알아보기 위해 두 개의 개체 인스턴스를 비교합니다. Object.Equals()
를 올바르게 사용하더라도 때때로 버그가 있는 코드가 있음을 나타낼 수 있습니다.
public class AccountGroup
{
private int gid;
public int Gid
{
get { return gid; }
set { gid = value; }
}
}
...
public class CompareGroup
{
public bool compareGroups(AccountGroup group1, AccountGroup group2)
{
return group1.Equals(group2); //Equals() is not implemented in AccountGroup
}
}
equals()
메서드는 equals()
를 구현하지 않는 개체에서 호출됩니다.equals()
를 명시적으로 구현하지 않는 클래스(또는 임의의 수퍼 클래스/인터페이스)에서 equals()
를 호출하면 java.lang.Object
에서 상속된 equals()
메서드를 호출하게 됩니다. 개체 멤버 필드 또는 기타 속성을 비교하는 대신, Object.equals()
는 동일한지 알아보기 위해 두 개의 개체 인스턴스를 비교합니다. Object.equals()
를 올바르게 사용하더라도 때때로 버그가 있는 코드가 있음을 나타낼 수 있습니다.
public class AccountGroup
{
private int gid;
public int getGid()
{
return gid;
}
public void setGid(int newGid)
{
gid = newGid;
}
}
...
public class CompareGroup
{
public boolean compareGroups(AccountGroup group1, AccountGroup group2)
{
return group1.equals(group2); //equals() is not implemented in AccountGroup
}
}
finalize()
메서드는 super.finalize()
를 호출해야 합니다.finalize()
메서드로 super.finalize()
를 호출하는 것이 좋은 방법이라고 설명합니다[1].super.finalize()
호출이 생략된 것입니다.
protected void finalize() {
discardNative();
}
private void writeObject(java.io.ObjectOutputStream out) throws IOException;
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;
private void readObjectNoData() throws ObjectStreamException;
getOutputStream
호출 후 getWriter()
를 호출하거나 그 반대로 수행하는 경우도 잘못입니다.HttpServletRequest
을 전달하거나, HttpServletResponse
를 리디렉션하거나 서블릿의 출력 스트림 버퍼를 플러시하면 연결된 스트림이 커밋됩니다. 추가 플러시 또는 리디렉션 등, 이어지는 버퍼 재설정 또는 스트림 커밋은 IllegalStateException
으로 이어질 수 있습니다.ServletOutputStream
또는 PrintWriter
중 하나를 사용하여(두 가지 모두는 안 됨) 응답 스트림에 데이터를 쓸 수 있습니다. getOutputStream()
을 호출한 후 getWriter()
를 호출하거나 또는 그 반대의 경우에도 IllegalStateException
이 발생합니다.IllegalStateException
은 응답 핸들러가 실행 완료되는 것을 막아 응답을 취소합니다. 이로 인해 서버 불안정이 발생할 수 있는데, 이는 서블릿이 잘못 구현되었다는 의미입니다.예제 2: 반대로 다음 코드는 요청이 전달되고 나면
public class RedirectServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
...
OutputStream out = res.getOutputStream();
...
// flushes, and thereby commits, the output stream
out.flush();
out.close(); // redirecting the response causes an IllegalStateException
res.sendRedirect("http://www.acme.com");
}
}
PrintWriter
의 버퍼에 쓰거나 플러시를 시도합니다.
public class FlushServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
...
// forwards the request, implicitly committing the stream
getServletConfig().getServletContext().getRequestDispatcher("/jsp/boom.jsp").forward(req, res);
...
// IllegalStateException; cannot redirect after forwarding
res.sendRedirect("http://www.acme.com/jsp/boomboom.jsp");
PrintWriter out = res.getWriter();
// writing to an already-committed stream will not cause an exception,
// but will not apply these changes to the final output, either
out.print("Writing here does nothing");
// IllegalStateException; cannot flush a response's buffer after forwarding the request
out.flush();
out.close();
}
}
Content-Length
헤더가 음수로 설정됩니다.Content-Length
헤더를 설정한다는 것은 개발자가0
또는Content-Length
를 설정합니다.
URL url = new URL("http://www.example.com");
HttpURLConnection huc = (HttpURLConnection)url.openConnection();
huc.setRequestProperty("Content-Length", "-1000");
Content-Length
헤더가 음수로 설정됩니다.Content-Length
헤더를 설정한다는 것은 개발자가0
또는Content-Length
헤더를 음수로 잘못 설정합니다.
xhr.setRequestHeader("Content-Length", "-1000");
ToString()
이 배열에서 호출됩니다.ToString()
의 호출은 개발자가 배열의 내용을 문자열로 반환하는 데 관심이 있다는 의미입니다. 그러나 배열에서 ToString()
을 직접 호출하면 배열의 형식을 포함하는 문자열 값이 반환됩니다.System.String[]
을 출력합니다.
String[] stringArray = { "element 1", "element 2", "element 3", "element 4" };
System.Diagnostics.Debug.WriteLine(stringArray.ToString());
toString()
이 배열에서 호출됩니다.toString()
의 호출은 개발자가 배열의 내용을 문자열로 반환하는 데 관심이 있다는 의미입니다. 그러나 배열에서 toString()
을 직접 호출하면 배열의 형식 및 메모리의 해시코드를 포함하는 문자열 값이 반환됩니다.[Ljava.lang.String;@1232121
을 출력합니다.
String[] strList = new String[5];
...
System.out.println(strList);