๐น๏ธ ๋ชจ์ํดํน ์ฒดํ ๋์
๐น๏ธ ๋ชจ์ํดํน ์ฒดํ ๋ฐ๋ผํ๊ธฐ โถ
STEP_1) test ๊ณ์ ๋ก๊ทธ์ธSTEP_2) ๊ด๋ฆฌ์ ์์ด๋(admin) ์ ๋ณด ํ์ธ
STEP_3) SQL ์ธ์ ์
์ฝ๋๋ฅผ ์ด์ฉํ์ฌ ๊ด๋ฆฌ์ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ ์๋
STEP_4) ๊ด๋ฆฌ๋ผ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ์ด ๊ฐ๋ฅํ๋ฉฐ, FLAG ๊ฐ ํ์ธ ๊ฐ๋ฅ
[LDAP ์ธ์ ์
]โถ
O ์ฌ์ฉ์ ์
๋ ฅ ๊ฐ์ ๋น์ ์์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ํฌํจํ ํ ์
๋ ฅ์ ์๋ํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผํ ์ ์๋ ์ทจ์ฝ์
O ๊ทผ๊ฑฐ ์๋ฃ
โ ์ฃผ์์ ๋ณดํต์ ๊ธฐ๋ฐ์์ค ๊ธฐ์ ์ ์ทจ์ฝ์ ๋ถ์ ํ๊ฐ ์์ธ ๊ฐ์ด๋(p.657)
โ OWASP TOP10 2021
O ํ๋จ ๊ธฐ์ค
์ํธ | ์์์ LDAP ์ฟผ๋ฆฌ ์
๋ ฅ์ ๋ํ ๊ฒ์ฆ์ด ์ด๋ฃจ์ด์ ธ ๋ณ์กฐ๋ ์ฟผ๋ฆฌ๊ฐ ์คํ๋์ง ์๋ ๊ฒฝ์ฐ |
์ทจ์ฝ | ์์์ LDAP ์ฟผ๋ฆฌ ์
๋ ฅ์ ๋ํ ๊ฒ์ฆ์ด ์ด๋ฃจ์ด์ง์ง ์์ ๋ณ์กฐ๋ ์ฟผ๋ฆฌ๊ฐ ์คํ๋๋ ๊ฒฝ์ฐ |
O ์ ๊ฒ ๋ฐฉ๋ฒ
- ์ฌ์ฉ์ ์
๋ ฅ ๊ฐ ๋ด์ LDAP์์ ์์ผ๋ ๋ฌธ์๋ก ์ฌ์ฉ๋๋ * ๊ธฐํธ๋ฅผ ์
๋ ฅํ์ฌ ๋ฐํ๋๋ ๋ฐ์ดํฐ ๋์ ๋ณํ๋ฅผ ํ์ธํ๋ค.
- [*);cn;], [*));cn;], [*)));cn;], [*)));cn;]์ ๋ฐฉ๋ฒ์ผ๋ก ) ๊ธฐํธ๋ฅผ ์ถ๊ฐํ์ฌ ์๋ฌ๊ฐ ๋ฐ์ํ๋์ง ํ์ธํ๋ค.
O ์กฐ์น ๋ฐฉ๋ฒ
- ์
๋ ฅ์ด LDAP ์ฟผ๋ฆฌ์ ํฌํจ๋์ด์ผ ํ๋ ๊ฒฝ์ฐ๋ผ๋ฉด, ์
๋ ฅํ ๊ฐ์ ํ์ฉ๋ ๋ฌธ์๋ก๋ง ๊ฒ์ฆ์ด ๋์ด์ผ ํ๊ณ , LDAP์ฟผ๋ฆฌ์ ์ํฅ์ ์ฃผ๋ ํน์๋ฌธ์ ์
๋ ฅ ์ ํ
- ํน์๋ฌธ์๋ฅผ ์ฌ์ฉํ์ฌ์ผ ํ๋ ๊ฒฝ์ฐ &lsquo=', '+', '<', '>' ๋ฑ์ ํน์ ๋ฌธ์์ ๊ฒฝ์ฐ ์คํ ๋ช
๋ น์ด ์๋ ์ผ๋ฐ ๋ฌธ์๋ก ์ธ์๋๋๋ก ์ฒ๋ฆฌ
# ํํฐ๋ง ๋์
' | " | -- | # | ( |
) | = | */ | /* | + |
< | > | user_tables | user_table_columns | user_table_columns |
column_name | syscolumns | union | select | insert |
drop | update | and | or | if |
join | substring | from | where | declare |
substr | openrowset | xp | sysobject | declare |
* | from | & | | |
|
O ์ํ์ด ์ฝ๋ฉ(Secure Coding) ์์
# JAVA โถ
private void searchRecord(String userSN, String userPassword) throwsย
NamingException {
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
try {
DirContext dctx = new InitialDirContext(env);
SearchControls sc = new SearchControls();
String[] attributeFilter = {"cn", "mail" };
sc.setReturningAttributes(attributeFilter);
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
String base = "dc=example,dc=com";
ย ย ย ย // userSN๊ณผ userPassword ๊ฐ์์ LDAP ํํฐ๋ฅผ ์กฐ์ํ ์ ์๋ ๋ฌธ์์ด์ ์ ๊ฑฐํ๊ณ ์ฌ์ฉ
if (!userSN.matches("[๏ฟฆ๏ฟฆw๏ฟฆ๏ฟฆs]*") || !userPassword.matches("[๏ฟฆ๏ฟฆw]*")) {
throw new IllegalArgumentException("Invalid input");
}
String filter = "(&(sn=" + userSN + ")(userPassword=" + userPassword + "))";
NamingEnumeration<!--?--> results = dctx.search(base, filter, sc);
while (results.hasMore()) {
SearchResult sr = (SearchResult) results.next();
Attributes attrs = sr.getAttributes();
Attribute attr = attrs.get("cn");
......
}
dctx.close();
} catch (NamingException e) {
ย ย ย ย // ์์ธ ์ฒ๋ฆฌ
}
}
# C# โถ
static void SearchRecord(string userSN, string userPW){
try {
DirectoryEntry oDE;
oDE = new DirectoryEntry(GetStrPath(), userSN, userPW);
// userSN๊ณผ userPW ๋ก ์ธ์ฆ ํ์ LDAP ์ฟผ๋ฆฌ๋ฅผ ์คํ
foreach(DirectoryEntry objChildDE om oDE.Children) {
ย ย ย ย ย ย ย ย .....
}
ย ย } catch (NamingException e)
{
ย ย ย ย // ์์ธ ์ฒ๋ฆฌ
}
}
# C โถ
void LDAPInjection() {
char *filter = getenv(“Filter”);
int error_code; int i;
LDAP *ld = NULL;
LDAPMessage *result;
// ์ ๋ณด๋ฅผ ์๊ณ ์ถ์ ์ฌ์ฉ์์ ์ด๋ฆ์ ๊ณ ์ ๊ฐ์ผ๋ก ์ฌ์ฉ
for(i = 0; *(filter + i) != 0; i++) {
// ๊ณต๊ฒฉ ๊ฐ๋ฅํ ๋ฌธ์์ด ๊ฒ์ฌ
switch(*(filter + i)) {
case '*':
case '(':
case ')':
.....
return;
}
}
error_code = ldap_search_ext_s(ld, FIND_DN, LDAP_SCOPE_BASE, filter, NULL, 0, NULL, NULL, LDAP_NO_LIMIT, LDAP_NO_LIMIT, &result);
}
[SQL ์ธ์ ์
]โถ
O ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฐ๋๋ ์น ์์ฉํ๋ก๊ทธ๋จ์์ ์
๋ ฅ๋ ๋ฐ์ดํฐ์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฆ์ ํ์ง ์์ ๊ฒฝ์ฐ, ๊ณต๊ฒฉ์๊ฐ ์
๋ ฅ ํผ ๋ฐ URL ์
๋ ฅ๋์ SQL๋ฌธ์ ์ฝ์
ํ์ฌ DB๋ก๋ถํฐ ์ ๋ณด๋ฅผ ์ด๋ํ๊ฑฐ๋ ์กฐ์ํ ์ ์๋ ์ทจ์ฝ์
O ๊ทผ๊ฑฐ ์๋ฃ
โ ์ฃผ์์ ๋ณดํต์ ๊ธฐ๋ฐ์์ค ๊ธฐ์ ์ ์ทจ์ฝ์ ๋ถ์ ํ๊ฐ ์์ธ ๊ฐ์ด๋(p.661)
โ OWASP TOP10 2021
O ํ๋จ ๊ธฐ์ค
์ํธ | ์์์ SQL ์ฟผ๋ฆฌ ์
๋ ฅ์ ๋ํ ๊ฒ์ฆ์ด ์ด๋ฃจ์ด์ ธ ์์์ ์ฟผ๋ฆฌ๊ฐ ์คํ๋์ง ์๋ ๊ฒฝ์ฐ |
์ทจ์ฝ | ์์์ SQL ์ฟผ๋ฆฌ ์
๋ ฅ์ ๋ํ ๊ฒ์ฆ์ด ์ด๋ฃจ์ด์ง์ง ์๋ ๊ฒฝ์ฐ |
O ์ ๊ฒ ๋ฐฉ๋ฒ
- ๋ณ์ ๊ฐ์ ํฐ๋ฐ์ดํ(“), ์์๋ฐ์ดํ(‘), ์ธ๋ฏธ์ฝ๋ก (;) ๋ฑ์ ์
๋ ฅํ ํ, DB error๊ฐ ์ผ์ด๋๋์ง ํ์ธํ๋ค.
- ['and'a&rsquo='a, 'and'a&rsquo='b], [and 1=1, and 1=2]์ ์ธํธ์ ๊ฐ์ ๊ฐ๊ฐ ์ฝ์
ํ์ฌ ์ ์ ๋ณ์ ๊ฐ์ ๋ณด๋ธ ํ๋ฉด๊ณผ [๋์ผํ๋ฉด, ๋ค๋ฅธํ๋ฉด]์ ๋ฐ์์ด ์๋์ง ํ์ธํ๋ค.
- ๋ก๊ทธ์ธ ํ๋ฉด์ ๊ฒฝ์ฐ ์์ด๋๋ ํจ์ค์๋ ๋ณ์ ๊ฐ์ ['or 1=1 –], ['or&rdquo='] ๋ฑ์ SQL ์ฟผ๋ฆฌ๋ฌธ์ ์
๋ ฅํ ํ ๋ก๊ทธ์ธ์ด ๋๋์ง ์๋ํ๋ค.
O ์กฐ์น ๋ฐฉ๋ฒ
- ๋ฌธ์์ด ์ ํจ์ฑ ๊ฒ์ฆ ๋ก์ง ๊ตฌํ
# ์ฌ์ฉ์ ์
๋ ฅ ๊ฐ ์ ํ ํน์ ๋ฌธ์ (DB์ ๋ฐ๋ผ ๋ฌธ์๊ฐ ๋ฌ๋ผ์ง ์ ์์)
๋ฌธ์ | ์ค๋ช
|
' | ๋ฌธ์ ๋ฐ์ดํฐ ๊ตฌ๋ถ ๊ธฐํธ |
; | ์ฟผ๋ฆฌ ๊ตฌ๋ถ ๊ธฐํธ |
--, # | ํด๋น๋์ธ ์ฃผ์ ๊ตฌ๋ถ ๊ธฐํธ |
/*, */ | /*์ */ ์ฌ์ด ๊ตฌ๋ฌธ ์ฃผ์ |
- Dynamic SQL ๊ตฌ๋ฌธ ์ฌ์ฉ ๊ธ์ง ๋ฐ ํ๋ผ๋ฏธํฐ ๋ฌธ์์ด ๊ฒ์ฌ ํ์ ์ ์ฉ
- ์ค๋ฅ์ ๋ํ ์์ธ ์ฒ๋ฆฌ
: ๊ณต๊ฒฉ์์๊ฒ ์์คํ
์ ๋ณด ๋ฑ์ ์ ๊ณตํ ์ ์๋ ์๋ฌ ๋ฉ์์ง๋ฅผ ํตํ ์ ๋ณด ๋
ธ์ถ ์ต์ํ
: ์๋ฌ ๋ฉ์์ง ๋ฐ DBMS์์ ์ ๊ณตํ๋ ์๋ฌ ์ฝ๋๊ฐ ๋
ธ์ถ๋์ง ์๋๋ก ์์ธ ์ฒ๋ฆฌ
- ์น ๋ฐฉํ๋ฒฝ์ ํตํ Injection ๊ณต๊ฒฉ ์ฐจ๋จ ์ ์ฑ
์ ์ฉ
- ํํฐ๋ง ๋ฑ ์
๋ ฅ ๊ฐ ๊ฒ์ฆ ํ๋ก์ธ์ค๋ ์๋ฒ ์ฌ์ด๋ ์คํฌ๋ฆฝํธ๋ก ๊ตฌํ
O ์ํ์ด ์ฝ๋ฉ(Secure Coding) ์์
# JAVA โถ
import java.util.regex.Matcher;
import java.util.regex.Pattern;
final Pattern SpecialChars = Pattern.compile("['\"\\-#,-()@=*/+]");
// ์ธ์ ์
์ ์ฌ์ฉ๋๋ ํน์๋ฌธ์ ํํฐ๋ง
UserInput = SpecialChars.matcher(UserInput).replaceAll("");
// ์ธ์ ์
์ ์ฌ์ฉ๋๋ SQL ๋ช
๋ น์ด ํํฐ๋ง
final String regex = "(union|select|from|where|case|then|dual|having|group by)";ย
final Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
final Matcher matcher = pattern.matcher(UserInput);
if(matcher.find())
{
out.println("");
}
# PHP โถ
// ์ธ์ ์
์ ์ฌ์ฉ๋๋ ํน์๋ฌธ์ ํํฐ๋ง
$UserInput = preg_replace("/[\r\n\s\t\'\;\"\=\-\-\#\/*]+/","", $UserInput);
// ์ธ์ ์
์ ์ฌ์ฉ๋๋ SQL ๋ช
๋ น์ด ํํฐ๋ง
if(preg_match('/(union|select|from|where)/i', $UserInput)) {
$this–>Error_popup('No SQL-Injection');
}
# php.ini ์ค์ ๋ณ๊ฒฝ โถ
- php.ini ์ค์ ์ค magic_quotes_gpc ๊ฐ์ On์ผ๋ก ์ค์
Magic quotes
// Magic quotes for incoming GET/POST/Cookie data
// off์์ on์ผ๋ก ๋ณ๊ฒฝํ๋ค.
magic_quotes_gpc = ON ;
// Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc.
magic_quotes_runtime = Off
// Use Sybase-style magic quotes (escape ' with " instead of \').
magic_quotes_sybase = Off
[SSI ์ธ์ ์
]โถ
O SSI(Server-Side Includes)๋ HTML๋ฌธ์ ๋ด ๋ณ์ ๊ฐ์ผ๋ก ์
๋ ฅ๋ ํ, ์ด๋ฅผ ์๋ฒ๊ฐ ์ฒ๋ฆฌํ๊ฒ ๋๋๋ฐ, ์ด ๋ ์ธ์ ์
๋ช
๋ น๋ฌธ์ด ์ํ๋์ด ์๋ฒ ๋ฐ์ดํฐ ์ ๋ณด๊ฐ ๋์ถ๋๋ ์ทจ์ฝ์
* SSI(Server-Side Includes) : CGI ํ๋ก๊ทธ๋จ์ ์์ฑํ๊ฑฐ๋ ํน์ ์๋ฒ ์ฌ์ด๋ ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ๋ ์ธ์ด๋ก, ์น ์๋ฒ๊ฐ ์ฌ์ฉ์์๊ฒ ํ์ด์ง๋ฅผ ์ ๊ณตํ๊ธฐ ์ ์ ๊ตฌ๋ฌธ์ ํด์ํ๋๋ก ์ง์ํ๋ ์ญํ
O ๊ทผ๊ฑฐ ์๋ฃ
โ ์ฃผ์์ ๋ณดํต์ ๊ธฐ๋ฐ์์ค ๊ธฐ์ ์ ์ทจ์ฝ์ ๋ถ์ ํ๊ฐ ์์ธ ๊ฐ์ด๋(p. 667)
โ OWASP TOP10 2021
O ํ๋จ ๊ธฐ์ค
์ํธ | ์ฌ์ฉ์ ์
๋ ฅ ๊ฐ์ ๋ํ ๊ฒ์ฆ์ด ์ด๋ฃจ์ด์ง๋ ๊ฒฝ์ฐ |
์ทจ์ฝ | ์ฌ์ฉ์ ์
๋ ฅ ๊ฐ์ ๋ํ ๊ฒ์ฆ์ด ์ด๋ฃจ์ด์ง์ง ์๋ ๊ฒฝ์ฐ |
O ์ ๊ฒ ๋ฐฉ๋ฒ
- ๋ณ์ ๊ฐ์ <!–#echo var="DOCUMENT_ROOT" –>๋ฅผ ์ฝ์
ํ์ฌ ํ์ ํ์ด์ง์ ์ฌ์ดํธ์ ํ ๋๋ ํฐ๋ฆฌ๊ฐ ํ์๋๋์ง ํ์ธํ๋ค.
- ๋ณ์ ๊ฐ์ <!–#exec cmd="ls -al" –>๋ฅผ ์ฝ์
ํ์ฌ ํ์ ํ์ด์ง์ ๋๋ ํฐ๋ฆฌ์ ํ์ผ ๋ฆฌ์คํธ๊ฐ ํ์๋๋์ง ํ์ธํ๋ค.
O ์กฐ์น ๋ฐฉ๋ฒ
- ์ฌ์ฉ์๊ฐ ์
๋ ฅ์ด ๊ฐ๋ฅํ ๋ฌธ์๋ค์ ์ ํํ์ฌ ์ ํด์ง ๋ฌธ์๋ฅผ ์ ์ธํ ๋๋จธ์ง ๋ชจ๋ ๋ฌธ์์ ๋ํ์ฌ ํํฐ๋ง ์ํ
: ํํฐ๋ง ๋์์ GET ์ง์ ๋ฌธ์์ด, POST ๋ฐ์ดํฐ, ์ฟ ํค, URL, ๊ทธ๋ฆฌ๊ณ ์ผ๋ฐ์ ์ผ๋ก ๋ธ๋ผ์ฐ์ ์ ์น ์๋ฒ๊ฐ ์ฃผ๊ณ ๋ฐ๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ํฌํจ
# ํน์๋ฌธ์์ ๋ํ Entity ํํ ์์
๋ณ๊ฒฝ ์ | < | > | " | ( | ) | $ | & |
๋ณ๊ฒฝ ํ | < | > | " | ( | ) | # | & |
[XPath ์ธ์ ์
]โถ
O XML ๋ฌธ์๋ฅผ ์กฐํํ ๊ฒฝ์ฐ ์
๋ ฅ ๊ฐ ์กฐ์์ ํตํด XQuery๋ XPath์ ๊ฐ์ ์ฟผ๋ฆฌ๋ฌธ์ ๊ตฌ์กฐ๋ฅผ ์์๋ก ๋ณ๊ฒฝํ์ฌ ํ๊ฐ๋์ง ์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๊ฑฐ๋ ์ธ์ฆ์ ์ฐจ๋ฅผ ์ฐํํ ์ ์๋ ์ทจ์ฝ์
O ๊ทผ๊ฑฐ ์๋ฃ
โ ์ฃผ์์ ๋ณดํต์ ๊ธฐ๋ฐ์์ค ๊ธฐ์ ์ ์ทจ์ฝ์ ๋ถ์ ํ๊ฐ ์์ธ ๊ฐ์ด๋(p.669)
โ OWASP TOP10 2021
O ํ๋จ ๊ธฐ์ค
์ํธ | ์ฟผ๋ฆฌ ์
๋ ฅ ๊ฐ์ ๋ํด ๊ฒ์ฆ์ด ์ด๋ฃจ์ด์ง๋ ๊ฒฝ์ฐ |
์ทจ์ฝ | ์ฟผ๋ฆฌ ์
๋ ฅ ๊ฐ์ ๋ํ ๊ฒ์ฆ์ด ์ด๋ฃจ์ด์ง์ง ์๋ ๊ฒฝ์ฐ |
O ์ ๊ฒ ๋ฐฉ๋ฒ
- ['and' a'='a, 'and' a'='b], [ and 1=1, and 1=2]์ ์ธํธ์ ๊ฐ์ ๊ฐ๊ฐ ์ฝ์
ํ์ฌ ์ ์ ๋ณ์ ๊ฐ์ ๋ณด๋ธ ํ๋ฉด๊ณผ [๋์ผํ๋ฉด, ๋ค๋ฅธํ๋ฉด]์ ๋ฐ์์ด ์๋์ง ํ์ธํ๋ค.
- ๋ค์ ๊ฐ์ ์
๋ ฅํด์ ์๋ฌ๊ฐ ๋ฐ์ํ์ง ์๋์ง ํ์ธํ๋ค.
: 'or count(parent::*[position()=1])=0 or 'a'='b
: 'or count(parent::*[position()=1])>0 or 'a'='b
: 1 or count(parent::*[position()=1])=0
: 1 or count(parent::*[position()=1])>0
O ์กฐ์น ๋ฐฉ๋ฒ
- XPath ์ฟผ๋ฆฌ์ ์
๋ ฅ ๊ฐ์ด ์
๋ ฅ๋๋ ๊ฒฝ์ฐ, ( ) = ' [ ] : , * / ๋ฑ ํน์๋ฌธ์ ๋ฐ ์ฟผ๋ฆฌ ์์ฝ์ด ํํฐ๋ง
- ํน์ ํน์๋ฌธ์ ๋ฟ๋ง ์๋๋ผ ํ์ฉ๋ ๋ฌธ์ ์ด์ธ์ ๋ชจ๋ ์
๋ ฅ ์ ํ
O ์ํ์ด ์ฝ๋ฉ(Secure Coding) ์์
# JAVA (์ฌ์ XQuery ๊ณจ๊ฒฉ ์์ฑ) โถ
[login.xq ํ์ผ]
declare variable $loginID as xs:string external;
declare variable $password as xs:string external;
// users/user[@loginID=$loginID and @password=$password]
// XQuery๋ฅผ ์ด์ฉํ XPath Injection ๋ฐฉ์ง
String nm = props.getProperty("name");
String pw = props.getProperty("password");
Document doc = new Builder().build("users.xml");
// ํ๋ผ๋ฏธํฐํ ๋ ์ฟผ๋ฆฌ๊ฐ ๋ด๊ฒจ์๋ login.xq๋ฅผ ์ฝ์ด์์ ํ๋ผ๋ฏธํฐํ ๋ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๋ค.
XQuery xquery = new XQueryFactory().createXQuery(new File("login.xq"));
Map vars = new HashMap();
// ๊ฒ์ฆ๋์ง ์์ ์ธ๋ถ ๊ฐ์ธ nm, pw๋ฅผ ํ๋ผ๋ฏธํฐํ ๋ ์ฟผ๋ฆฌ์ ํ๋ผ๋ฏธํฐ๋ก ์ค์ ํ๋ค.
vars.put("loginID", nm);
vars.put("password", pw);
// ํ๋ผ๋ฏธํฐํ ๋ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋ฏ๋ก ์ธ๋ถ ๊ฐ์ ๊ฒ์ฆ์์ด ์ฌ์ฉํ์ฌ๋ ์์ ํ๋ค.
Nodes results = xquery.execute(doc, null, vars).toNodes();
for (int i=0; i<results.size(); i++){
system.out.println(results.get(i).toXML());
}
# JAVA โถ
// XPath ์ฝ์
์ ์ ๋ฐํ ์ ์๋ ๋ฌธ์๋ค์ ์
๋ ฅ ๊ฐ์์ ์ ๊ฑฐ
public String XPathFilter(String input) {
if (input != null)
return input.replaceAll("[',๏ฟฆ๏ฟฆ[]", "");
} else {
return "";
}
}
......
// ์ธ๋ถ ์
๋ ฅ ๊ฐ์ ์ฌ์ฉ
String nm = XPathFilter(props.getProperty("name"));
String pw = XPathFilter(props.getProperty("password"));
......
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
......
// ์ธ๋ถ ์
๋ ฅ ๊ฐ์ธ nm, pw๋ฅผ ๊ฒ์ฆํ์ฌ ์ฟผ๋ฆฌ๋ฌธ์ ์์ฑํ๋ฏ๋ก ์์ ํ๋ค.
XPathExpression expr = xpath.compile("//users/user[login/text()='"+nm+"' and password/text()='"+pw+"']/home_dir/text()");
๐น๏ธ ๋ชจ์ํดํน ์ฒดํ ๋์
๐น๏ธ ๋ชจ์ํดํน ์ฒดํ ๋ฐ๋ผํ๊ธฐ โถ
STEP_1) test ๊ณ์ ๋ก๊ทธ์ธSTEP_2) ๊ด๋ฆฌ์ ์์ด๋(admin) ์ ๋ณด ํ์ธ
STEP_3) SQL ์ธ์ ์ ์ฝ๋๋ฅผ ์ด์ฉํ์ฌ ๊ด๋ฆฌ์ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ ์๋
STEP_4) ๊ด๋ฆฌ๋ผ ๊ณ์ ์ผ๋ก ๋ก๊ทธ์ธ์ด ๊ฐ๋ฅํ๋ฉฐ, FLAG ๊ฐ ํ์ธ ๊ฐ๋ฅ
[LDAP ์ธ์ ์ ]โถ
O ์ฌ์ฉ์ ์ ๋ ฅ ๊ฐ์ ๋น์ ์์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ํฌํจํ ํ ์ ๋ ฅ์ ์๋ํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผํ ์ ์๋ ์ทจ์ฝ์
O ๊ทผ๊ฑฐ ์๋ฃ
โ ์ฃผ์์ ๋ณดํต์ ๊ธฐ๋ฐ์์ค ๊ธฐ์ ์ ์ทจ์ฝ์ ๋ถ์ ํ๊ฐ ์์ธ ๊ฐ์ด๋(p.657)
โ OWASP TOP10 2021
O ํ๋จ ๊ธฐ์ค
O ์ ๊ฒ ๋ฐฉ๋ฒ
- ์ฌ์ฉ์ ์ ๋ ฅ ๊ฐ ๋ด์ LDAP์์ ์์ผ๋ ๋ฌธ์๋ก ์ฌ์ฉ๋๋ * ๊ธฐํธ๋ฅผ ์ ๋ ฅํ์ฌ ๋ฐํ๋๋ ๋ฐ์ดํฐ ๋์ ๋ณํ๋ฅผ ํ์ธํ๋ค.
- [*);cn;], [*));cn;], [*)));cn;], [*)));cn;]์ ๋ฐฉ๋ฒ์ผ๋ก ) ๊ธฐํธ๋ฅผ ์ถ๊ฐํ์ฌ ์๋ฌ๊ฐ ๋ฐ์ํ๋์ง ํ์ธํ๋ค.
O ์กฐ์น ๋ฐฉ๋ฒ
- ์ ๋ ฅ์ด LDAP ์ฟผ๋ฆฌ์ ํฌํจ๋์ด์ผ ํ๋ ๊ฒฝ์ฐ๋ผ๋ฉด, ์ ๋ ฅํ ๊ฐ์ ํ์ฉ๋ ๋ฌธ์๋ก๋ง ๊ฒ์ฆ์ด ๋์ด์ผ ํ๊ณ , LDAP์ฟผ๋ฆฌ์ ์ํฅ์ ์ฃผ๋ ํน์๋ฌธ์ ์ ๋ ฅ ์ ํ
- ํน์๋ฌธ์๋ฅผ ์ฌ์ฉํ์ฌ์ผ ํ๋ ๊ฒฝ์ฐ &lsquo=', '+', '<', '>' ๋ฑ์ ํน์ ๋ฌธ์์ ๊ฒฝ์ฐ ์คํ ๋ช ๋ น์ด ์๋ ์ผ๋ฐ ๋ฌธ์๋ก ์ธ์๋๋๋ก ์ฒ๋ฆฌ
# ํํฐ๋ง ๋์
O ์ํ์ด ์ฝ๋ฉ(Secure Coding) ์์
# JAVA โถ
# C# โถ
# C โถ
[SQL ์ธ์ ์ ]โถ
O ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฐ๋๋ ์น ์์ฉํ๋ก๊ทธ๋จ์์ ์ ๋ ฅ๋ ๋ฐ์ดํฐ์ ๋ํ ์ ํจ์ฑ ๊ฒ์ฆ์ ํ์ง ์์ ๊ฒฝ์ฐ, ๊ณต๊ฒฉ์๊ฐ ์ ๋ ฅ ํผ ๋ฐ URL ์ ๋ ฅ๋์ SQL๋ฌธ์ ์ฝ์ ํ์ฌ DB๋ก๋ถํฐ ์ ๋ณด๋ฅผ ์ด๋ํ๊ฑฐ๋ ์กฐ์ํ ์ ์๋ ์ทจ์ฝ์
O ๊ทผ๊ฑฐ ์๋ฃ
โ ์ฃผ์์ ๋ณดํต์ ๊ธฐ๋ฐ์์ค ๊ธฐ์ ์ ์ทจ์ฝ์ ๋ถ์ ํ๊ฐ ์์ธ ๊ฐ์ด๋(p.661)
โ OWASP TOP10 2021
O ํ๋จ ๊ธฐ์ค
O ์ ๊ฒ ๋ฐฉ๋ฒ
- ๋ณ์ ๊ฐ์ ํฐ๋ฐ์ดํ(“), ์์๋ฐ์ดํ(‘), ์ธ๋ฏธ์ฝ๋ก (;) ๋ฑ์ ์ ๋ ฅํ ํ, DB error๊ฐ ์ผ์ด๋๋์ง ํ์ธํ๋ค.
- ['and'a&rsquo='a, 'and'a&rsquo='b], [and 1=1, and 1=2]์ ์ธํธ์ ๊ฐ์ ๊ฐ๊ฐ ์ฝ์ ํ์ฌ ์ ์ ๋ณ์ ๊ฐ์ ๋ณด๋ธ ํ๋ฉด๊ณผ [๋์ผํ๋ฉด, ๋ค๋ฅธํ๋ฉด]์ ๋ฐ์์ด ์๋์ง ํ์ธํ๋ค.
- ๋ก๊ทธ์ธ ํ๋ฉด์ ๊ฒฝ์ฐ ์์ด๋๋ ํจ์ค์๋ ๋ณ์ ๊ฐ์ ['or 1=1 –], ['or&rdquo='] ๋ฑ์ SQL ์ฟผ๋ฆฌ๋ฌธ์ ์ ๋ ฅํ ํ ๋ก๊ทธ์ธ์ด ๋๋์ง ์๋ํ๋ค.
O ์กฐ์น ๋ฐฉ๋ฒ
- ๋ฌธ์์ด ์ ํจ์ฑ ๊ฒ์ฆ ๋ก์ง ๊ตฌํ
# ์ฌ์ฉ์ ์ ๋ ฅ ๊ฐ ์ ํ ํน์ ๋ฌธ์ (DB์ ๋ฐ๋ผ ๋ฌธ์๊ฐ ๋ฌ๋ผ์ง ์ ์์)
- Dynamic SQL ๊ตฌ๋ฌธ ์ฌ์ฉ ๊ธ์ง ๋ฐ ํ๋ผ๋ฏธํฐ ๋ฌธ์์ด ๊ฒ์ฌ ํ์ ์ ์ฉ
- ์ค๋ฅ์ ๋ํ ์์ธ ์ฒ๋ฆฌ
: ๊ณต๊ฒฉ์์๊ฒ ์์คํ ์ ๋ณด ๋ฑ์ ์ ๊ณตํ ์ ์๋ ์๋ฌ ๋ฉ์์ง๋ฅผ ํตํ ์ ๋ณด ๋ ธ์ถ ์ต์ํ
: ์๋ฌ ๋ฉ์์ง ๋ฐ DBMS์์ ์ ๊ณตํ๋ ์๋ฌ ์ฝ๋๊ฐ ๋ ธ์ถ๋์ง ์๋๋ก ์์ธ ์ฒ๋ฆฌ
- ์น ๋ฐฉํ๋ฒฝ์ ํตํ Injection ๊ณต๊ฒฉ ์ฐจ๋จ ์ ์ฑ ์ ์ฉ
- ํํฐ๋ง ๋ฑ ์ ๋ ฅ ๊ฐ ๊ฒ์ฆ ํ๋ก์ธ์ค๋ ์๋ฒ ์ฌ์ด๋ ์คํฌ๋ฆฝํธ๋ก ๊ตฌํ
O ์ํ์ด ์ฝ๋ฉ(Secure Coding) ์์
# JAVA โถ
# PHP โถ
# php.ini ์ค์ ๋ณ๊ฒฝ โถ
- php.ini ์ค์ ์ค magic_quotes_gpc ๊ฐ์ On์ผ๋ก ์ค์
[SSI ์ธ์ ์ ]โถ
O SSI(Server-Side Includes)๋ HTML๋ฌธ์ ๋ด ๋ณ์ ๊ฐ์ผ๋ก ์ ๋ ฅ๋ ํ, ์ด๋ฅผ ์๋ฒ๊ฐ ์ฒ๋ฆฌํ๊ฒ ๋๋๋ฐ, ์ด ๋ ์ธ์ ์ ๋ช ๋ น๋ฌธ์ด ์ํ๋์ด ์๋ฒ ๋ฐ์ดํฐ ์ ๋ณด๊ฐ ๋์ถ๋๋ ์ทจ์ฝ์
* SSI(Server-Side Includes) : CGI ํ๋ก๊ทธ๋จ์ ์์ฑํ๊ฑฐ๋ ํน์ ์๋ฒ ์ฌ์ด๋ ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ๋ ์ธ์ด๋ก, ์น ์๋ฒ๊ฐ ์ฌ์ฉ์์๊ฒ ํ์ด์ง๋ฅผ ์ ๊ณตํ๊ธฐ ์ ์ ๊ตฌ๋ฌธ์ ํด์ํ๋๋ก ์ง์ํ๋ ์ญํ
O ๊ทผ๊ฑฐ ์๋ฃ
โ ์ฃผ์์ ๋ณดํต์ ๊ธฐ๋ฐ์์ค ๊ธฐ์ ์ ์ทจ์ฝ์ ๋ถ์ ํ๊ฐ ์์ธ ๊ฐ์ด๋(p. 667)
โ OWASP TOP10 2021
O ํ๋จ ๊ธฐ์ค
O ์ ๊ฒ ๋ฐฉ๋ฒ
- ๋ณ์ ๊ฐ์ <!–#echo var="DOCUMENT_ROOT" –>๋ฅผ ์ฝ์ ํ์ฌ ํ์ ํ์ด์ง์ ์ฌ์ดํธ์ ํ ๋๋ ํฐ๋ฆฌ๊ฐ ํ์๋๋์ง ํ์ธํ๋ค.
- ๋ณ์ ๊ฐ์ <!–#exec cmd="ls -al" –>๋ฅผ ์ฝ์ ํ์ฌ ํ์ ํ์ด์ง์ ๋๋ ํฐ๋ฆฌ์ ํ์ผ ๋ฆฌ์คํธ๊ฐ ํ์๋๋์ง ํ์ธํ๋ค.
O ์กฐ์น ๋ฐฉ๋ฒ
- ์ฌ์ฉ์๊ฐ ์ ๋ ฅ์ด ๊ฐ๋ฅํ ๋ฌธ์๋ค์ ์ ํํ์ฌ ์ ํด์ง ๋ฌธ์๋ฅผ ์ ์ธํ ๋๋จธ์ง ๋ชจ๋ ๋ฌธ์์ ๋ํ์ฌ ํํฐ๋ง ์ํ
: ํํฐ๋ง ๋์์ GET ์ง์ ๋ฌธ์์ด, POST ๋ฐ์ดํฐ, ์ฟ ํค, URL, ๊ทธ๋ฆฌ๊ณ ์ผ๋ฐ์ ์ผ๋ก ๋ธ๋ผ์ฐ์ ์ ์น ์๋ฒ๊ฐ ์ฃผ๊ณ ๋ฐ๋ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ํฌํจ
# ํน์๋ฌธ์์ ๋ํ Entity ํํ ์์
[XPath ์ธ์ ์ ]โถ
O XML ๋ฌธ์๋ฅผ ์กฐํํ ๊ฒฝ์ฐ ์ ๋ ฅ ๊ฐ ์กฐ์์ ํตํด XQuery๋ XPath์ ๊ฐ์ ์ฟผ๋ฆฌ๋ฌธ์ ๊ตฌ์กฐ๋ฅผ ์์๋ก ๋ณ๊ฒฝํ์ฌ ํ๊ฐ๋์ง ์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๊ฑฐ๋ ์ธ์ฆ์ ์ฐจ๋ฅผ ์ฐํํ ์ ์๋ ์ทจ์ฝ์
O ๊ทผ๊ฑฐ ์๋ฃ
โ ์ฃผ์์ ๋ณดํต์ ๊ธฐ๋ฐ์์ค ๊ธฐ์ ์ ์ทจ์ฝ์ ๋ถ์ ํ๊ฐ ์์ธ ๊ฐ์ด๋(p.669)
โ OWASP TOP10 2021
O ํ๋จ ๊ธฐ์ค
O ์ ๊ฒ ๋ฐฉ๋ฒ
- ['and' a'='a, 'and' a'='b], [ and 1=1, and 1=2]์ ์ธํธ์ ๊ฐ์ ๊ฐ๊ฐ ์ฝ์ ํ์ฌ ์ ์ ๋ณ์ ๊ฐ์ ๋ณด๋ธ ํ๋ฉด๊ณผ [๋์ผํ๋ฉด, ๋ค๋ฅธํ๋ฉด]์ ๋ฐ์์ด ์๋์ง ํ์ธํ๋ค.
- ๋ค์ ๊ฐ์ ์ ๋ ฅํด์ ์๋ฌ๊ฐ ๋ฐ์ํ์ง ์๋์ง ํ์ธํ๋ค.
: 'or count(parent::*[position()=1])=0 or 'a'='b
: 'or count(parent::*[position()=1])>0 or 'a'='b
: 1 or count(parent::*[position()=1])=0
: 1 or count(parent::*[position()=1])>0
O ์กฐ์น ๋ฐฉ๋ฒ
- XPath ์ฟผ๋ฆฌ์ ์ ๋ ฅ ๊ฐ์ด ์ ๋ ฅ๋๋ ๊ฒฝ์ฐ, ( ) = ' [ ] : , * / ๋ฑ ํน์๋ฌธ์ ๋ฐ ์ฟผ๋ฆฌ ์์ฝ์ด ํํฐ๋ง
- ํน์ ํน์๋ฌธ์ ๋ฟ๋ง ์๋๋ผ ํ์ฉ๋ ๋ฌธ์ ์ด์ธ์ ๋ชจ๋ ์ ๋ ฅ ์ ํ
O ์ํ์ด ์ฝ๋ฉ(Secure Coding) ์์
# JAVA (์ฌ์ XQuery ๊ณจ๊ฒฉ ์์ฑ) โถ
# JAVA โถ