๋ํ์ ์ธ ๋งํฌ์ ์ธ์ด์ธ XML ๋ฐ์ดํฐ์ ๋ํด ๋์ ์ฟผ๋ฆฌ๋ฌธ์ ์์ฑํ ๋ XQuery๋ฅผ ์ฌ์ฉํ๊ณค ํฉ๋๋ค. ์ด ๋ ์ธ๋ถ ์ ๋ ฅ ๊ฐ์ ๋ํด ์ ์ ํ ๊ฒ์ฆ ์ ์ฐจ๊ฐ ํ์ํ๋ฐ์. ๋ง์ผ ๊ฒ์ฆ ์ ์ฐจ๊ฐ ์์ ๊ฒฝ์ฐ์๋ ๊ณต๊ฒฉ์๊ฐ ์ฟผ๋ฆฌ๋ฌธ์ ๊ตฌ์กฐ๋ฅผ ์์๋ก ์กฐ์ํ ์ ์๊ฒ ๋ฉ๋๋ค. ๊ทธ๋์ ์ ์์ ์ธ ์ฟผ๋ฆฌ๊ฐ ์คํ๋์ด ํ๊ฐ๋์ง ์์ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๊ฑฐ๋ ์ธ์ฆ ์ ์ฐจ๋ฅผ ์ฐํํ ์ ์๊ฒ ๋์ด ์ํ์ด ๋ ์ ์์ต๋๋ค.
์ด ๊ณต๊ฒฉ์ ๋ฐ๋ก XQuery ์ฝ์ (XQuery Injection) ์ด๋ผ๊ณ ํฉ๋๋ค.
XQuery Injection์ ๊ณต๊ฒฉ ์๋ฆฌ๋ฅผ ์ ๋ฆฌํด๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ ์์๋ก ์ด๋ฃจ์ด์ง๋๋ค.
- ๊ณต๊ฒฉ์๊ฐ XQuery Injection ์๋
- XML ๋ฐ์ดํฐ์ ๋ํ ์กฐ์๋ ๋์ ์ฟผ๋ฆฌ๋ฌธ ์์ฑ
- ์กฐ์๋ XQuery๋ฌธ ์คํ
- ์๋ฒ๋ ์คํ๋ ๊ฒฐ๊ณผ ์ฆ, ๊ณต๊ฒฉ ๊ฒฐ๊ณผ๋ฅผ ๊ณต๊ฒฉ์์๊ฒ ์ ๋ฌ
XQuery Injection์ ์๋ฐฉํ๊ธฐ ์ํ ์์ ํ ์ฝ๋ฉ ๊ธฐ๋ฒ์ ํฌ๊ฒ 2๊ฐ์ง๊ฐ ์์ต๋๋ค.
- XQuery์ ์ฌ์ฉ๋๋ ์ธ๋ถ ์ ๋ ฅ๊ฐ์ ๋ํ์ฌ ํน์๋ฌธ์๋ ์ฟผ๋ฆฌ ์์ฝ์ด๋ฅผ ํํฐ๋งํฉ๋๋ค
- XQuery๋ฅผ ์ฌ์ฉํ ์ฟผ๋ฆฌ๋ฌธ์ string์ ์ฐ๊ฒฐํ๋ ํํ๊ฐ ์๋ ํ๋ผ๋ฏธํฐํ๋ ์ฟผ๋ฆฌ๋ฌธ ์ฌ์ฉํฉ๋๋ค
์๋ ์์ ๋ฅผ ํตํด ์กฐ๊ธ ๋ ๊ตฌ์ฒด์ ์ผ๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค.
๋จผ์ ์์ ํ์ง ์์ ์ฝ๋ ์ ์ฒด๋ถํฐ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ด ์์ ๋ ์ธ๋ถ๋ก๋ถํฐ ์ ๋ ฅ๋ฐ์ ๊ฐ(name)์ executeQuery๋ฅผ ์ฌ์ฉํ ์ง์ ์์ฑ ๋ฌธ์์ด ์ธ์ ์์ฑ์ ์ฌ์ฉํ๋ ๊ณผ์ ์ ์ฝ๋์ ๋๋ค.
......
// ์ธ๋ถ๋ก๋ถํฐ ์
๋ ฅ ๊ฐ(name) ๋ฐ์
String name = props.getProperty("name");
//
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=rootDir");
javax.naming.directory.DirContext ctx = new InitialDirContext(env);
javax.xml.xquery.XQDataSource xqds = (javax.xml.xquery.XQDataSource) ctx.lookup("xqj/personnel");
javax.xml.xquery.XQConnection conn = xqds.getConnection();
//์์ ํ์ง ์์ ์ฝ๋
String es = "doc('users.xml')/userlist/user[uname='" + name + "']";
// ์
๋ ฅ๊ฐ์ด Xquery ์ธ์๋ก ์ฌ์ฉ
XQPreparedExpression expr = conn.prepareExpression(es);
XQResultSequence result = expr.executeQuery();
while (result.next())
{
String str = result.getAtomicValue();
if (str.indexOf('>') < 0)
{
System.out.println(str);
}
......
์ด ๋, ์ธ๋ถ๋ก๋ถํฐ ๋ฐ์ ์ ๋ ฅ ๊ฐ์ ๋ฐ์ ๊ฒ์ ๋ฐ๋ก XQuery๋ฌธ์ ํฌํจ์์ผ ์คํํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
String es = "doc('users.xml')/userlist/user[uname='" + name + "']";
์ด ๊ฒฝ์ฐ, ๋ง์ผ ์ธ๋ถ ์ ๋ ฅ๊ฐ์ด XQuery ์์ ์ฟผ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๋ณ๊ฒฝ์ํค๋ ๊ตฌ๋ฌธ์ผ ๊ฒฝ์ฐ, XQuery Injection์ด ์คํ๋ฉ๋๋ค.
name์ ๊ฐ์ something' or '1'='1
๊ณผ ๊ฐ์ด ์ ๋ฌํ๊ฒ ๋๋ฉด doc('users.xml')/userlist/user[uname='something' or '1'='1'
์ ๊ฐ์ ์ง์๋ฌธ์ ์ํํ๊ฒ ๋ฉ๋๋ค. ์ด๋ก ์ธํด ํ์ผ ๋ด์ ๋ชจ๋ ๊ฐ์ ์ถ๋ ฅํ ์ ์๊ฒ ๋์ด ์ ๋ณด๊ฐ ์ ์ถ๋ ์ํ์ด ์์ต๋๋ค.
๋ฐ๋ผ์ ์ด๋ฅผ ๋ง๊ธฐ ์ํด ์๋์ ๊ฐ์ด ์ธ์(parameter) ํ์์ผ๋ก ์ ๋ฌ๋ ์ ์๋๋ก ์ฝ๋๋ฅผ ์์ ํด์ผ ํฉ๋๋ค.
String es = "doc('user.xml')/userlist/user[uname='$xpathname']";
expr.bindString(new QName("xpathname"), name, null);
XQResultSequence result = expr.executeQuery();
preparedExpression์ ์ฌ์ฉํ์ฌ bindString, bindInt ๋ฑ์ ํจ์๋ฅผ ํตํด ์ธ์ ํ์์ผ๋ก ์ ๋ฌํ๋ ๋ฐฉ์์ธ๋ฐ์. ์ด๋ฅผ ํตํด ์ธ๋ถ์์ ์ ๋ ฅ๋ฐ์ ๊ฐ์ ๋จ์ํ ๋ฌธ์์ด๋ก ์ทจ๊ธ๋๋ฉฐ XQuery ์์ ์ฟผ๋ฆฌ ๋ฌธ๋ฒ์ผ๋ก ์ธ์๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ์ธ๋ถ ์ ๋ ฅ์ผ๋ก๋ถํฐ ์ฟผ๋ฆฌ ๊ตฌ์กฐ๊ฐ ๋ฐ๋๋ ๊ฒ์ ๋ง์ ์ ์์ต๋๋ค.
์์ ํ ์ฝ๋์ ์ ์ฒด๋ ์๋์ ๊ฐ์ต๋๋ค.
......
// ์ธ๋ถ๋ก๋ถํฐ ์
๋ ฅ ๊ฐ(name) ๋ฐ์
String name = props.getProperty("name");
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, "ldap://localhost:389/o=rootDir");
javax.naming.directory.DirContext ctx = new InitialDirContext(env);
javax.xml.xquery.XQDataSource xqds = (javax.xml.xquery.XQDataSource) ctx.lookup("xqj/personnel");
javax.xml.xquery.XQConnection conn = xqds.getConnection();
//์์ ํ ์ฝ๋
String es = "doc('users.xml')/userlist/user[uname='$xpathname']";
// ์
๋ ฅ๊ฐ์ด Xquery ์ธ์๋ก ์ฌ์ฉ
XQPreparedExpression expr = conn.prepareExpression(es);
expr.bindString(new QName("xpathname"), name, null);
XQResultSequence result = expr.executeQuery();
while (result.next())
{
String str = result.getAtomicValue();
if (str.indexOf('>') < 0)
{
System.out.println(str);
}
ํน์ ์์ดํ ์ ํ๋งค๊ฐ๊ฒฉ์ ์์์ค๋ ์ฝ๋ ์ค ์์ ํ์ง ์์ ์ฝ๋์ ์์๋ฅผ ํ๋ฒ ๋ณผ๊น์?
๋ฐ์ดํฐ์ ๋ํ ์ฝ๋๊ฐ ๋ค์๊ณผ ๊ฐ์ด ์ฃผ์ด์ ธ์์ต๋๋ค. โฌ๏ธ
<?xml version="1.0"?>
<items>
...
<price>
<selling_price>
<iem001>100</iem001>
<iem002>150</iem001>
...
</selling_price>
<buying_price>
<iem001>50</iem001>
<iem002>140</iem001>
...
</buying_price>
</price>
...
</items>
์ฌ๊ธฐ์์ ํน์ ์์ดํ ์ ํ๋งค๊ฐ๊ฒฉ์ ์์์๋ด ์๋ค.
string์ ์ฐ๊ฒฐํ๋ ํํ๋ก ๊ตฌ์ฑ๋ ์ฟผ๋ฆฌ๋ฌธ์ผ๋ก ์์ฑ์ ํ์ต๋๋ค. โฌ๏ธ
String itemId = request.getParameter(ITEM_ID);
XQExpression xqe = conn.createExpression();
String xqueryString = "doc('items.xml')/items/price/selling_price/" + itemId;
์ด๋ ๊ฒ ๋๋ฉด ์ ์ ํ ๊ฒ์ฆ ์ ์ฐจ๋ฅผ ๊ฑฐ์น์ง ์๊ณ ๋ ํน์ ์์ดํ ์ ๊ตฌ๋งค๊ฐ๊ฒฉ์ ๋ถ๋ฌ์ฌ ์ ์์ต๋๋ค. ๋๋ฌธ์ ์ํ์ง ์๋ ์ ๋ณด๊ฐ ๋ ธ์ถ๋ ์ํ์ด ์์ต๋๋ค.
๐ก ๊ทธ๋ผ ์ด๋ป๊ฒ ์์ ํ ์ฝ๋๋ฅผ ์งค ์ ์์๊น์?์ด์ ์ ์์ ํ์ง ์์ ์ฝ๋์์๋ ๋์ ์ฟผ๋ฆฌ๋ฌธ์ ์์ฑํ ๋ ์ฌ์ฉํ๋ ์ธ๋ถ ์ ๋ ฅ ๊ฐ์ ๋ํด ์ ์ ํ ๊ฒ์ฆ ๊ณผ์ ์ ๊ฑฐ์น์ง ์์์ต๋๋ค. ์ด์ ๋ฌ๋ฆฌ ์ด๋ฒ์๋ ๋์ ์์ฑ์ ํ๋ ๋์ ์ ์ง์๋ฌธ์ PrepareExpression์ผ๋ก ์ค๋นํ ํ, ์ ๋ ฅ๊ฐ์ ์ธ์๋ก ์ ๋ฌํ์ฌ ์์ ์ฑ์ ๋์ฌ์ฃผ์์ต๋๋ค.
String xqueryString = "doc('items.xml')/items/price/selling_price/'$itemId';
//๋ณด์์ฑ์ ์ํด prepareExpression์ผ๋ก ์ง์๋ฌธ ์ค๋น
xqe = conn.prepareExpression(xqueryString);
์ด๋ฐ ๋ฐฉ์์ผ๋ก ์ฝ๋๋ฅผ ์ง๋ฉด, ์ง์๋ฌธ์ ๋ํ ๊ตฌ๋ฌธ ๋ถ์์ด ๋์ด์ ๋์ ์ผ๋ก ์ด๋ฃจ์ด์ง์ง ์๊ฒ ๋ฉ๋๋ค. ๋ฐ๋ผ์ ์ ๋ ฅ ๊ฐ์ ์ง์๋ฌธ์ ๊ตฌ์กฐ๊ฐ ๋ฐ๋๋ ๊ฒ์ ๋ง์ ์ํ์ง ์๋ ์ ๋ณด๊ฐ ๋ ธ์ถ๋๋ ํ์์ ๋ฐฉ์งํฉ๋๋ค.
if (command.equals(GET_ITEM_PRICE))
{
String itemId = request.getParameter(ITEM_ID);
xqe.bindString(new QName("itemId"), itemId, null);
XQResultSequence rs = xqe.executeQuery();
...
}
์์ ํ ์ฝ๋์ ์์ ํ์ง ์์ ์์์ ์ ์ฒด ์ฝ๋์ ๋๋ค.
โฌ๏ธ ์ ์ฒด ์ฝ๋
์์ ํ์ง ์์ ์ฝ๋
public class Service extends HttpServlet
{
private final String COMMAND_PARAM = "command";
// Command ๊ด๋ จ์ ์
private final String GET_ITEM_PRICE = "get_item_price";
private final String ITEM_ID = "item_id";
private XQDataSource xqs;
private XQConnection conn;
public Service()
{
...
xqs = new SednaXQDataSource();
xqs.setProperty("serverName", "localhost");
xqs.setProperty("databaseName", "test");
conn = xqs.getConnection("SYSTEM", "MANAGER");
...
}
...
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException
{
String command = request.getParameter(COMMAND_PARAM);
...
if (command.equals(GET_ITEM_PRICE))
{
String itemId = request.getParameter(ITEM_ID);
XQExpression xqe = conn.createExpression();
String xqueryString = "doc('items.xml')/items/price/selling_price/" + itemId;
XQResultSequence rs = xqe.executeQuery(xqueryString);
...
}
...
}
...
}
์์ ํ ์ฝ๋
public class Service extends HttpServlet
{
private final String COMMAND_PARAM = "command";
// Command ๊ด๋ จ์ ์
private final String GET_ITEM_PRICE = "get_item_price";
private final String ITEM_ID = "item_id";
private XQDataSource xqs;
private XQConnection conn;
private XQPrepareExpression xqe;
public Service()
{
...
xqs = new SednaXQDataSource();
xqs.setProperty("serverName", "localhost");
xqs.setProperty("databaseName", "test");
conn = xqs.getConnection("SYSTEM", "MANAGER");
String xqueryString = "doc('items.xml')/items/price/selling_price/'$itemId';
//๋ณด์์ฑ์ ์ํด prepareExpression์ผ๋ก ์ง์๋ฌธ ์ค๋น
xqe = conn.prepareExpression(xqueryString);
...
}
...
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
ServletException, IOException
{
String command = request.getParameter(COMMAND_PARAM)
...
if (command.equals(GET_ITEM_PRICE))
{
String itemId = request.getParameter(ITEM_ID);
xqe.bindString(new QName("itemId"), itemId, null);
XQResultSequence rs = xqe.executeQuery();
...
}
...
}
...
}
๋ผ. ์ถ์ฒ
ํ์ ์์ ๋ถ_JAVA ์ํ์ด์ฝ๋ฉ ๊ฐ์ด๋
ํ์ ์์ ๋ถ_C ์ํ์ด์ฝ๋ฉ ๊ฐ์ด๋