null
인지 검사하기 전에 null
이 될 수 있는 포인터를 역참조할 경우 발생합니다. 검사 후 역참조(dereference-after-check) 오류는 프로그램이 null
인지 여부를 명시적으로 검사하지만, null
인 것으로 알려진 포인터를 역참조할 때 발생합니다. 이 유형의 오류는 철자 오류 또는 프로그래머의 실수로 발생합니다. 저장 후 역참조(dereference-after-store) 오류는 프로그램이 명시적으로 포인터를 null
로 설정하고 이를 나중에 역참조할 경우에 발생합니다. 이 오류는 프로그래머가 선언된 상태의 변수를 null
로 초기화하여 발생하는 경우가 많습니다.foo
가 null
임을 확인한 다음 잘못 역참조합니다. if
문에서 검사할 때 foo
가 null
이면 null
dereference가 발생하여 null 포인터 예외가 일어납니다.예제 2: 다음 코드에서 프로그래머는 변수
if (foo is null) {
foo.SetBar(val);
...
}
foo
가 null
이 아닌 것으로 가정한 다음 개체를 역참조하여 이 가정을 확인합니다. 그러나 프로그래머는 나중에 foo
를 null
에 대해 검사함으로써 가정을 반박합니다. if
문에서 검사할 때 foo
가 null
이 되면 역참조될 때도 null
이 되어 null 포인터 예외가 발생할 수 있습니다. 역참조가 안전하지 않거나 이후의 검사가 필요하지 않게 됩니다.예제 3: 다음 코드에서 프로그래머는 명시적으로 변수
foo.SetBar(val);
...
if (foo is not null) {
...
}
foo
를 null
로 설정합니다. 나중에 프로그래머는 개체의 null
값을 검사하기 전에 foo
를 역참조합니다.
Foo foo = null;
...
foo.SetBar(val);
...
}
null
인지 검사하기 전에 null
이 될 수 있는 포인터를 역참조할 경우 발생합니다. 검사 후 역참조(dereference-after-check) 오류는 프로그램이 null
인지 여부를 명시적으로 검사하지만, null
인 것으로 알려진 포인터를 역참조할 때 발생합니다. 이 유형의 오류는 철자 오류 또는 프로그래머의 실수로 발생합니다. 저장 후 역참조(dereference-after-store) 오류는 프로그램이 명시적으로 포인터를 null
로 설정하고 이를 나중에 역참조할 경우에 발생합니다. 이 오류는 프로그래머가 선언된 상태의 변수를 null
로 초기화하여 발생하는 경우가 많습니다.ptr
이 NULL
이 아닌 것으로 가정합니다. 이 가정은 프로그래머가 포인터를 역참조하면 명시적인 것이 됩니다. 프로그래머가 NULL
에 대해 ptr
을 검사하면 이 가정이 반박됩니다. if
문에서 검사할 때 ptr
이 NULL
이 되면 역참조될 때도 NULL
이 되어 조각화 오류가 발생할 수 있습니다.예제 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
로 설정합니다. 나중에 프로그래머는 개체의 null
값을 검사하기 전에 ptr
를 역참조합니다.
*ptr = NULL;
...
ptr->field = val;
...
}
null
인지 여부를 명시적으로 검사하지만, null
인 것으로 알려진 개체를 역참조할 때 발생합니다. 이 유형의 오류는 철자 오류 또는 프로그래머의 실수로 발생합니다.foo
이 null
임을 확인한 다음 실수로 역참조합니다. if
문에서 검사할 때 foo
가 null
이면 null
dereference가 발생하여 null 포인터 예외가 일어납니다.
if (foo == null) {
foo.setBar(val);
...
}
Content-Disposition
헤더가 잘못 구성되었거나 공격자가 HTTP 응답의 Content-Type
및/또는 Content-Disposition
헤더를 제어할 수 있거나 대상 응용 프로그램에 브라우저에서 기본적으로 렌더링되지 않는 Content-Type
이 포함되어 있습니다.ContentNegotiationManager
를 사용하여 다양한 응답 형식을 동적으로 생성하는 경우 RFD 공격을 가능하게 하는 데 필요한 조건을 충족합니다.ContentNegotiationManager
는 요청 경로 확장자를 기반으로 응답 형식을 결정하고 JAF(Java Activation Framework)를 사용하여 클라이언트의 요청 형식과 더 잘 일치하는 Content-Type
을 찾도록 구성되었습니다. 또한 클라이언트에서는 요청의 Accept
헤더로 전송되는 미디어 유형을 통해 응답 콘텐트 유형을 지정할 수도 있습니다.예제 2: 다음 예제에서 이 응용 프로그램은 요청의
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="favorPathExtension" value="true" />
<property name="useJaf" value="true" />
</bean>
Accept
헤더로 응답의 콘텐트 유형을 결정할 수 있도록 구성되어 있습니다.
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="ignoreAcceptHeader" value="false" />
</bean>
ContentNegotiationManagerFactoryBean
속성은 기본적으로 다음과 같이 설정됩니다.useJaf
: true
favorPathExtension
: true
ignoreAcceptHeader
: false
Example 1
의 구성을 통해 공격자는 다음과 같은 악성 URL을 작성합니다.ContentNegotiationManager
는 Java Activation Framework(activation.jar이 클래스 경로에 있는 경우)를 사용하여 지정된 파일 확장자의 미디어 유형을 확인하고 응답의 ContentType
헤더를 그에 따라 설정하려고 합니다. 이 예제에서는 파일 확장자가 "bat"이므로 Content-Type
헤더는 application/x-msdownload
입니다(정확한 Content-Type
은 서버 OS 및 JAF 구성에 따라 달라질 수 있음). 결과적으로 피해자가 이 악성 URL을 방문하면 피해자의 컴퓨터는 공격자가 제어하는 콘텐트가 포함된 ".bat" 파일 다운로드를 자동으로 시작합니다. 이 파일이 실행되면 피해자 시스템에서 공격자의 페이로드에 지정된 모든 명령이 실행됩니다.
...
host_name = request->get_form_field( 'host' ).
CALL FUNCTION 'FTP_CONNECT'
EXPORTING
USER = user
PASSWORD = password
HOST = host_name
RFC_DESTINATION = 'SAPFTP'
IMPORTING
HANDLE = mi_handle
EXCEPTIONS
NOT_CONNECTED = 1
OTHERS = 2.
...
int rPort = Int32.Parse(Request.Item("rPort"));
...
IPEndPoint endpoint = new IPEndPoint(address,rPort);
socket = new Socket(endpoint.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
socket.Connect(endpoint);
...
...
char* rPort = getenv("rPort");
...
serv_addr.sin_port = htons(atoi(rPort));
if (connect(sockfd,&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
...
...
ACCEPT QNAME.
EXEC CICS
READQ TD
QUEUE(QNAME)
INTO(DATA)
LENGTH(LDATA)
END-EXEC.
...
ServerSocket
개체를 만들고 HTTP 요청으로 읽어들인 포트 번호를 사용하여 소켓을 만듭니다.
<cfobject action="create" type="java" class="java.net.ServerSocket" name="myObj">
<cfset srvr = myObj.init(#url.port#)>
<cfset socket = srvr.accept()>
Passing user input to objects imported from other languages can be very dangerous.
final server = await HttpServer.bind('localhost', 18081);
server.listen((request) async {
final remotePort = headers.value('port');
final serverSocket = await ServerSocket.bind(host, remotePort as int);
final httpServer = HttpServer.listenOn(serverSocket);
});
...
func someHandler(w http.ResponseWriter, r *http.Request){
r.parseForm()
deviceName := r.FormValue("device")
...
syscall.BindToDevice(fd, deviceName)
}
String remotePort = request.getParameter("remotePort");
...
ServerSocket srvr = new ServerSocket(remotePort);
Socket skt = srvr.accept();
...
WebView
에서 페이지를 로드합니다.
...
WebView webview = new WebView(this);
setContentView(webview);
String url = this.getIntent().getExtras().getString("url");
webview.loadUrl(url);
...
var socket = new WebSocket(document.URL.indexOf("url=")+20);
...
char* rHost = getenv("host");
...
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)rHost, 80, &readStream, &writeStream);
...
<?php
$host=$_GET['host'];
$dbconn = pg_connect("host=$host port=1234 dbname=ticketdb");
...
$result = pg_prepare($dbconn, "my_query", 'SELECT * FROM pricelist WHERE name = $1');
$result = pg_execute($dbconn, "my_query", array("ticket"));
?>
...
filename := SUBSTR(OWA_UTIL.get_cgi_env('PATH_INFO'), 2);
WPG_DOCLOAD.download_file(filename);
...
host=request.GET['host']
dbconn = db.connect(host=host, port=1234, dbname=ticketdb)
c = dbconn.cursor()
...
result = c.execute('SELECT * FROM pricelist')
...
def controllerMethod = Action { request =>
val result = request.getQueryString("key").map { key =>
val user = db.getUser()
cache.set(key, user)
Ok("Cached Request")
}
Ok("Done")
}
...
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
var inputStream : NSInputStream?
var outputStream : NSOutputStream?
...
var readStream : Unmanaged<CFReadStream>?
var writeStream : Unmanaged<CFWriteStream>?
let rHost = getQueryStringParameter(url.absoluteString, "host")
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, rHost, 80, &readStream, &writeStream);
...
}
func getQueryStringParameter(url: String?, param: String) -> String? {
if let url = url, urlComponents = NSURLComponents(string: url), queryItems = (urlComponents.queryItems as? [NSURLQueryItem]) {
return queryItems.filter({ (item) in item.name == param }).first?.value!
}
return nil
}
...
...
Begin MSWinsockLib.Winsock tcpServer
...
Dim Response As Response
Dim Request As Request
Dim Session As Session
Dim Application As Application
Dim Server As Server
Dim Port As Variant
Set Response = objContext("Response")
Set Request = objContext("Request")
Set Session = objContext("Session")
Set Application = objContext("Application")
Set Server = objContext("Server")
Set Port = Request.Form("port")
...
tcpServer.LocalPort = Port
tcpServer.Accept
...
@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpAdvice() {
super("callback");
}
}
GET /api/latest.json?callback=myCallbackFunction
같은 요청의 경우 컨트롤러 메서드는 다음과 같은 응답을 생성합니다.
HTTP/1.1 200 Ok
Content-Type: application/json; charset=utf-8
Date: Tue, 12 Dec 2017 16:16:04 GMT
Server: nginx/1.12.1
Content-Length: 225
Connection: Close
myCallbackFunction({<json>})
Script
태그를 사용하여 JSONP 끝점에서 응답을 로드할 수 있으며 이 응답은 myCallbackFunction
함수의 실행으로 이어집니다. 공격자는 다른 콜백 이름을 사용하여 DOM을 탐색하고 상호 작용할 수 있습니다. 예를 들어 opener.document.body.someElemnt.firstChild.nextElementSibling.submit
은 대상 페이지에서 폼을 찾고 제출하는 데 사용될 수 있습니다.
def myJSONPService(callback: String) = Action {
val json = getJSONToBeReturned()
Ok(Jsonp(callback, json))
}
GET /api/latest.json?callback=myCallbackFunction
같은 요청의 경우 Example 1
에 설명된 컨트롤러 메서드는 다음과 같은 응답을 생성합니다.
HTTP/1.1 200 Ok
Content-Type: application/json; charset=utf-8
Date: Tue, 12 Dec 2017 16:16:04 GMT
Server: nginx/1.12.1
Content-Length: 225
Connection: Close
myCallbackFunction({<json>})
Script
태그를 사용하여 JSONP 끝점에서 응답을 로드할 수 있으며 이 응답은 myCallbackFunction
함수의 실행으로 이어집니다. 공격자는 다른 콜백 이름을 사용하여 DOM을 탐색하고 상호 작용할 수 있습니다. 예를 들어 opener.document.body.someElemnt.firstChild.nextElementSibling.submit
은 대상 페이지에서 폼을 찾고 제출하는 데 사용될 수 있습니다.sanitizeValue
를 false
로 설정하면 삭제되지 않은 입력이 Cross-Site Scripting과 같은 취약점으로 이어질 수 있습니다.sanitizeValue
속성은 값이 HTML 마크업에 적용될 때 HTML 삭제기를 실행할 것인지 여부를 결정합니다. 입력은 사용자로부터 직접 수신될 수 있으므로 안전하지 않은 것으로 간주될 수 있습니다. sanitizeValue
속성은 추가 입력 문자를 허용하는 등 여러 가지 이유로 인해 false
로 설정될 수 있습니다. 하지만 이렇게 하면 안전하지 않은 사용자 입력이 코드에서 부주의로 실행될 수 있습니다. sanitizeValue
속성을 기본값인 true
로 설정하는 것이 안전합니다.RichTextEditor
에서 sanitizeValue
속성을 false
로 설정합니다.
new RichTextEditor({
sanitizeValue: false,
value: input
}).placeAt("moreContent");
...
lv_uri = request->get_form_field( 'uri' ).
CALL METHOD cl_http_utility=>set_request_uri
EXPORTING
request = lo_request
uri = lv_uri.
...
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
...
PageReference ref = ApexPages.currentPage();
Map<String,String> params = ref.getParameters();
HttpRequest req = new HttpRequest();
req.setEndpoint(params.get('url'));
HTTPResponse res = new Http().send(req);
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
string url = Request.Form["url"];
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(url);
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
char *url = maliciousInput();
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, url);
CURLcode res = curl_easy_perform(curl);
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
...
final server = await HttpServer.bind('localhost', 18081);
server.listen((request) async {
final headers = request.headers;
final url = headers.value('url');
final client = IOClient();
final response = await client.get(Uri.parse(url!));
...
}
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
url := request.Form.Get("url")
res, err =: http.Get(url)
...
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
String url = request.getParameter("url");
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response1 = httpclient.execute(httpGet);
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
var http = require('http');
var url = require('url');
function listener(request, response){
var request_url = url.parse(request.url, true)['query']['url'];
http.request(request_url)
...
}
...
http.createServer(listener).listen(8080);
...
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
val url: String = request.getParameter("url")
val httpclient: CloseableHttpClient = HttpClients.createDefault()
val httpGet = HttpGet(url)
val response1: CloseableHttpResponse = httpclient.execute(httpGet)
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
$url = $_GET['url'];
$c = curl_init();
curl_setopt($c, CURLOPT_POST, 0);
curl_setopt($c,CURLOPT_URL,$url);
$response=curl_exec($c);
curl_close($c);
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
url = request.GET['url']
handle = urllib.urlopen(url)
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
url = req['url']
Net::HTTP.get(url)
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
def getFile(url: String) = Action { request =>
...
val url = request.body.asText.getOrElse("http://google.com")
ws.url(url).get().map { response =>
Ok(s"Request sent to $url")
}
...
}
http
또는 https
와는 다른 다음 프로토콜을 사용할 수 있게 됩니다.
// Set up the context data
VelocityContext context = new VelocityContext();
context.put( "name", user.name );
// Load the template
String template = getUserTemplateFromRequestBody(request);
RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
StringReader reader = new StringReader(template);
SimpleNode node = runtimeServices.parse(reader, "myTemplate");
template = new Template();
template.setRuntimeServices(runtimeServices);
template.setData(node);
template.initDocument();
// Render the template with the context data
StringWriter sw = new StringWriter();
template.merge( context, sw );
Example 1
은 Velocity
를 템플릿 엔진으로 사용합니다. 해당 엔진의 경우 공격자가 다음과 같은 템플릿을 제출하여 서버에서 임의의 명령을 실행할 수 있습니다.
$name.getClass().forName("java.lang.Runtime").getRuntime().exec(<COMMAND>)
app.get('/', function(req, res){
var template = _.template(req.params['template']);
res.write("<html><body><h2>Hello World!</h2>" + template() + "</body></html>");
});
Example 1
에서는 Node.js
응용 프로그램 내에서 Underscore.js
를 템플릿 엔진으로 사용합니다. 해당 엔진의 경우 공격자가 다음과 같은 템플릿을 제출하여 서버에서 임의의 명령을 실행할 수 있습니다.
<% cp = process.mainModule.require('child_process');cp.exec(<COMMAND>); %>
Jinja2
템플릿 엔진을 사용하여 렌더링되고 HTTP 요청에서 검색되는 방법을 보여 줍니다.
from django.http import HttpResponse
from jinja2 import Template as Jinja2_Template
from jinja2 import Environment, DictLoader, escape
def process_request(request):
# Load the template
template = request.GET['template']
t = Jinja2_Template(template)
name = source(request.GET['name'])
# Render the template with the context data
html = t.render(name=escape(name))
return HttpResponse(html)
Example 1
은 Jinja2
를 템플릿 엔진으로 사용합니다. 해당 엔진의 경우 공격자가 다음과 같은 템플릿을 제출하여 서버로부터 임의의 파일을 읽을 수 있습니다.예제 2: 다음 예제는 템플릿이
template={{''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}
Django
템플릿 엔진을 사용하여 렌더링되고 HTTP 요청에서 검색되는 방법을 보여 줍니다.
from django.http import HttpResponse
from django.template import Template, Context, Engine
def process_request(request):
# Load the template
template = source(request.GET['template'])
t = Template(template)
user = {"name": "John", "secret":getToken()}
ctx = Context(locals())
html = t.render(ctx)
return HttpResponse(html)
Example 2
은 Django
를 템플릿 엔진으로 사용합니다. 해당 엔진의 경우 공격자가 임의의 명령을 실행할 수 없지만 템플릿 컨텍스트의 모든 개체에 액세스할 수 있습니다. 이 예제에서는 암호 토큰을 컨텍스트에서 사용할 수 있으며 암호 토큰이 공격자에 의해 누출될 수 있습니다.
<http auto-config="true">
...
<session-management session-fixation-protection="none"/>
</http>
Example 1
에서는 공격자가 잘 알려지지 않은 웹 사이트 관련 공격에 적합하게 조정할 수 없는 직접적인 방법을 사용하여 이를 수행합니다. 하지만 그렇다고 안심해선 안 됩니다. 공격자는 이 공격의 한계를 극복할 수 있는 여러 가지 수단을 갖고 있습니다. 공격자가 사용하는 가장 흔한 방법은 대상 사이트에서 cross-site scripting 또는 HTTP response splitting 취약점을 이용하는 것입니다[1]. 피해자를 속여 JavaScript 또는 기타 코드를 피해자의 브라우저에 다시 돌려보내는 취약한 응용 프로그램에 악성 요청을 전송하도록 하여 공격자는 피해자가 공격자가 제어하는 세션 ID를 다시 사용하도록 하는 쿠키를 만들 수 있습니다.bank.example.com
및 recipes.example.com
과 같이 같은 최상위 도메인에 있는 경우, 한 응용 프로그램의 취약점 때문에 공격자가 도메인 example.com
[2]에 있는 응용 프로그램과의 모든 상호 작용에 사용할 고정 세션 ID로 쿠키를 설정할 수 있습니다.use_strict_mode
속성을 비활성화합니다.
ini_set("session.use_strict_mode", "0");
@SessionAttributes
주석이 있는 클래스는 Spring이 세션 개체의 모델 속성에 변경 사항을 복제하는 것을 의미합니다. 공격자가 모델 속성 내에 임의 값을 저장할 수 있으면 이러한 변경 사항은 응용 프로그램에서 신뢰할 수 있는 세션 개체로 복제됩니다. 세션 속성이 사용자가 수정할 수 없어야 하는 신뢰할 수 있는 데이터를 사용하여 초기화되는 경우 공격자는 세션 퍼즐링 공격을 수행하여 응용 프로그램 로직을 남용할 수 있습니다.
@Controller
@SessionAttributes("user")
public class HomeController {
...
@RequestMapping(value= "/auth", method=RequestMethod.POST)
public String authHandler(@RequestParam String username, @RequestParam String password, RedirectAttributes attributes, Model model) {
User user = userService.findByNamePassword(username, password);
if (user == null) {
// Handle error
...
} else {
// Handle success
attributes.addFlashAttribute("user", user);
return "redirect:home";
}
}
...
}
@SessionAttributes("user")
주석이 있으므로 세션에서 User
인스턴스를 로드하려고 시도하며, 이 인스턴스를 사용하여 암호 재설정 질문을 확인합니다.
@Controller
@SessionAttributes("user")
public class ResetPasswordController {
@RequestMapping(value = "/resetQuestion", method = RequestMethod.POST)
public String resetQuestionHandler(@RequestParam String answerReset, SessionStatus status, User user, Model model) {
if (!user.getAnswer().equals(answerReset)) {
// Handle error
...
} else {
// Handle success
...
}
}
}
user
인스턴스를 로드하려고 했습니다. 하지만 Spring은 이 요청을 검사하여 데이터를 모델 user
인스턴스로 바인딩하려고 시도할 것입니다. 받은 요청에 User
클래스에 바인딩될 수 있는 데이터가 포함된 경우, Spring은 받은 데이터를 사용자 세션 속성에 병합할 것입니다. 이 시나리오는 answerReset
쿼리 매개 변수의 임의 답변 및 동일한 값을 모두 제출함으로써 세션에 저장된 값을 재정의하는 방식으로 남용될 수 있습니다. 이러한 방법으로 공격자는 무작위 사용자에 대해 임의의 새 암호를 설정할 수 있습니다.
...
taintedConnectionStr = request->get_form_field( 'dbconn_name' ).
TRY.
DATA(con) = cl_sql_connection=>get_connection( `R/3*` && taintedConnectionStr ).
...
con->close( ).
CATCH cx_sql_exception INTO FINAL(exc).
...
ENDTRY.
...
sethostid(argv[1]);
...
sethostid()
호출을 제대로 수행하기 위해 프로세스에 권한을 부여해야 하지만 권한 없는 사용자도 프로그램을 호출할 수 있습니다. 이 예제의 코드를 사용하면 사용자 입력이 직접 시스템 설정 값을 제어할 수 있습니다. 공격자가 호스트 ID에 악성 값을 제공하면 네트워크상의 해당 시스템을 잘못 식별하거나 다른 의도하지 않은 동작을 일으킬 수 있습니다.
...
ACCEPT OPT1.
ACCEPT OPT2
COMPUTE OPTS = OPT1 + OPT2.
CALL 'MQOPEN' USING HCONN, OBJECTDESC, OPTS, HOBJ, COMPOCODE REASON.
...
...
<cfset code = SetProfileString(IniPath,
Section, "timeout", Form.newTimeout)>
...
Form.newTimeout
의 값이 시간 초과를 지정하는 데 사용되므로 공격자는 상당히 큰 수를 지정하여 응용 프로그램에 대해 denial of service(DoS) 공격을 시도할 수 있습니다.
...
catalog := request.Form.Get("catalog")
path := request.Form.Get("path")
os.Setenv(catalog, path)
...
HttpServletRequest
에서 문자열을 읽어 이를 데이터베이스 Connection
의 활성 카탈로그로 설정합니다.
...
conn.setCatalog(request.getParamter("catalog"));
...
http.IncomingMessage
요청 변수에서 문자열을 읽고 추가 V8 명령줄 플래그를 설정하는 데 사용합니다.
var v8 = require('v8');
...
var flags = url.parse(request.url, true)['query']['flags'];
...
v8.setFlagsFromString(flags);
...
<?php
...
$table_name=$_GET['catalog'];
$retrieved_array = pg_copy_to($db_connection, $table_name);
...
?>
...
catalog = request.GET['catalog']
path = request.GET['path']
os.putenv(catalog, path)
...
Connection
의 활성 범주로 설정합니다.
def connect(catalog: String) = Action { request =>
...
conn.setCatalog(catalog)
...
}
...
sqlite3(SQLITE_CONFIG_LOG, user_controllable);
...
Request
개체에서 문자열을 읽어 이를 데이터베이스 Connection
의 활성 카탈로그로 설정합니다.
...
Dim conn As ADODB.Connection
Set conn = New ADODB.Connection
Dim rsTables As ADODB.Recordset
Dim Catalog As New ADOX.Catalog
Set Catalog.ActiveConnection = conn
Catalog.Create Request.Form("catalog")
...
myModule.config(function($compileProvider){
$compileProvider.imgSrcSanitizationWhitelist(userInput);
});
/^(http(s)?|javascript):.*/
로 설정하는 경우, 응용 프로그램은 이미지 소스 URL 내에서 인라인 JavaScript의 사용을 허용하므로 Cross-Site Scripting 공격이 발생할 수 있습니다.ProcessWorkitemRequest.setAction()
호출에서 승인 작업을 제어하도록 허용합니다.
void processRequest() {
String workItemId = ApexPages.currentPage().getParameters().get('Id');
String action = ApexPages.currentPage().getParameters().get('Action');
Approval.ProcessWorkitemRequest req = new Approval.ProcessWorkitemRequest();
req.setWorkitemId(workItemId);
req.setAction(action);
Approval.ProcessResult res = Approval.process(req);
...
}
var hash = window.location.hash;
var myStartSymbol = decodeURIComponent(hash.substring(1, hash.length));
myModule.config(function($interpolateProvider){
$interpolateProvider.startSymbol(myStartSymbol);
});
clientaccesspolicy.xml
구성 파일을 적절히 설정하여 정책을 변경하는 것이 허용됩니다. 그러나, 지나치게 허용적인 도메인 간 정책을 사용하면 악성 응용 프로그램이 부적절한 방법으로 피해자 서비스와 통신하여 스푸핑, 데이터 도난, 릴레이 및 기타 공격으로 이어질 수 있기 때문에 설정 변경 시 주의해야 합니다.clientaccesspolicy.xml
을 보여줍니다.
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
*
를 domain
요소 uri
속성의 값으로 사용하면 모든 도메인의 응용 프로그램이 서비스에 연결할 수 있음을 나타냅니다.
...
public String inputValue {
get { return inputValue; }
set { inputValue = value; }
}
...
String queryString = 'SELECT Id FROM Contact WHERE (IsDeleted = false AND Name like \'%' + inputValue + '%\')';
result = Database.query(queryString);
...
SELECT Id FROM Contact WHERE (IsDeleted = false AND Name like '%inputValue%')
inputValue
에 작은따옴표가 들어 있지 않은 경우에만 정확하게 동작합니다. 공격자가 inputValue
에 name') OR (Name like '%
문자열을 입력하면 쿼리는 다음과 같습니다.
SELECT Id FROM Contact WHERE (IsDeleted = false AND Name like '%name') OR (Name like '%%')
name') OR (Name like '%
조건을 추가하면 where 절이 LIKE '%%'
조건을 사용하게 됩니다. 이 조건은 훨씬 간단한 다음 쿼리와 논리적으로 동일하게 되므로 쿼리가 모든 가능한 ID 값을 출력하게 합니다.
SELECT Id FROM Contact WHERE ... OR (Name like '%%')
...
public String inputValue {
get { return inputValue; }
set { inputValue = value; }
}
...
String queryString = 'Name LIKE \'%' + inputValue + '%\'';
String searchString = 'Acme';
String searchQuery = 'FIND :searchString IN ALL FIELDS RETURNING Contact (Id WHERE ' + queryString + ')';
List<List<SObject>> results = Search.query(searchQuery);
...
String searchQuery = 'FIND :searchString IN ALL FIELDS RETURNING Contact (Id WHERE Name LIKE '%' + inputValue + '%')';
inputValue
에 작은따옴표가 들어 있지 않은 경우에만 정확하게 동작합니다. 공격자가 inputValue
에 1%' OR Name LIKE '
문자열을 입력하면 쿼리는 다음과 같습니다.
String searchQuery = 'FIND :searchString IN ALL FIELDS RETURNING Contact (Id WHERE Name LIKE '%1%' OR Name LIKE '%%')';
OR Name like '%%'
조건을 추가하면 where 절이 LIKE '%%'
조건을 사용하므로, 쿼리가 문구 'map'이 포함된 모든 레코드를 출력하게 하며, 훨씬 간단한 다음 쿼리와 논리적으로 동일하게 됩니다.
FIND 'map*' IN ALL FIELDS RETURNING Contact (Id WHERE Name LIKE '%%')
String beans = getBeanDefinitionFromUser();
GenericApplicationContext ctx = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.loadBeanDefinitions(new UrlResource(beans));
ctx.refresh();
ACTUATOR
역할을 가진 사용자만 액세스할 수 있도록 보호됩니다.
management.security.enabled=false
endpoints.health.sensitive=false
@Component
public class CustomEndpoint implements Endpoint<List<String>> {
public String getId() {
return "customEndpoint";
}
public boolean isEnabled() {
return true;
}
public boolean isSensitive() {
return false;
}
public List<String> invoke() {
// Custom logic to build the output
...
}
}