فا

‫ برنامه‌نويسي امن با زبان جاوا – قوانين اعتبارسنجي ورودي و پاكسازي داده‌ها – قانون IDS00-J – قسمت دوم

IRCAR201310190
تاريخ: 29/07/92
اولين موضوعي كه به طور كلي در برنامه نويسي امن ( رجوع شود به مقاله اصول برنامه نويسي امن ) و همچنين در برنامه نويسي امن با زبان جاوا مورد توجه قرار مي گيرد مربوط به اعتبار سنجي ورودي و پاكسازي داده ها است. در اين موضوع چهارده قانون معرفي مي گردد كه سطوح امنيتي مختلفي دارند ( رجوع شود به مقاله برنامه‌نويسي امن با زبان جاوا – قوانين اعتبارسنجيورودي و پاكسازي داده‌ها - آشنايي ). اولين قانون از اين موضوع داراي داراي سطح امنيتي يك (L1) بوده و از بالاترين اولويت (P12) برخوردار مي باشد.
قانون IDS00-J - داده هاي نامطمئن را كه از مرزهاي معتمد عبور مي كنند پاكسازي نماييد.
در قسمت قبلي در مورد چگونگي پيش گيري از آسيب پذيري تزريق SQL توضيح داديم ، در اين قسمت به تزريق XML مي پردازيم.
تزريق XML
از آنجايي كه XML مستقل از پلتفرم بوده و قابليت انعطاف بالايي دارد، همچنين نسبتاً ساده است، استفاده از اين زبان در انواع برنامه هاي كاربردي از فراخواني هاي از راه دور توابع (RPC) گرفته تا ذخيره سازي سيستماتيك، تبادل و بازيابي داده گسترش پيدا كرده است. با اين وجود به علت تطبيق پذيري بالاي اين زبان، XML در برابر گستره وسيعي از حملات آسيب پذير است. يكي از اين حملات تزريق XML است.
كاربري كه اجازه وارد كردن يك XML ساخت يافته را به عنوان ورودي دارد، مي تواند محتويات يك فايل XML را با تزريق تگ هاي XML بازنويسي كند. اين تگ ها توسط تجزيه گر XML تفسير شده و به عنوان محتواي قابل اجرا دسته بندي مي شوند و به همين دليل ممكن است موجب بازنويسي بر روي برخي از اعضاي داده اي شوند.
براي مثال كد XML زير را كه از يك فروشگاه آنلاين تهيه شده است، در نظر بگيريد كه اساساً براي پرس و جوي يك پايگاه داده طراحي شده است. كاربر توانايي مشخص كردن تعداد آيتم هاي مورد نظر براي خريد را دارا مي باشد.
<item>
<description>Widget</description>
<price>500.0</price>
<quantity>1</quantity>
</item>
يك كاربر خرابكار ميتواند به جاي وارد كردن يك عدد رشته زير را در فيلد quantity وارد نمايد.
1</quantity><price>1.0</price><quantity>1
در نتيجه XML به صورت زير در مي آيد:
<item>
<description>Widget</description>
<price>500.0</price>
<quantity>1</quantity><price>1.0</price><quantity>1</quantity>
</item>
يك API ساده براي تجزيه گر XML(org.xml.sax and javax.xml.parsers.SAXParser) اين رشته را طوري تفسير مي كند كه قيمت دوم بر روي قيمت اول بازنويسي مي شود و در نتيجه قيمت آيتم برابر يك دلار محاسبه مي شود. حتي وقتي كه امكان اجراي چنين حمله اي نيز وجود نداشته باشد، مهاجم ممكن است توانايي تزريق كاراكترهاي خاصي را همچون بلوك هاي توضيحات و يا جداكننده هاي CDATA داشته باشد به طوري كه معناي XML را از بين ببرد.
يك نمونه ناسازگار با قانون
در اين نمونه ناسازگار با قانون جاري، يك تابع مشتري از يك تسلسل رشته اي ساده براي ساخت پرس و جوي XML براي ارسال به سرور استفاده مي كند. در اينجا امكان تزريق XML وجود دارد زيرا هيچگونه اعتبارسنجي داده ها انجام نمي شود.
private void createXMLStream(BufferedOutputStream outStream,
String quantity) throws IOException {
String xmlString;
xmlString = "<item>\n<description>Widget</description>\n" +
"<price>500.0</price>\n" +
"<quantity>" + quantity + "</quantity></item>";
outStream.write(xmlString.getBytes());
outStream.flush();
}
راه حل سازگار با قانون (ليست سفيد)
با توجه به داده هاي خاص و مفسرهاي دستور و تجزيه گرهايي كه داده ها به آنها فرستاده مي شوند، لازم است توابع متناسب براي پاكسازي ورودي نامطمئن از كاربر مورد استفاده قرار بگيرند. كد سازگار با قانون زير از ليست سفيد براي پاكسازي داده ها استفاده مي كند. در اين مثال تابع مقدار quantity را به عددي بين صفر و نه محدود مي سازد.
private void createXMLStream(BufferedOutputStream outStream,
String quantity) throws IOException {
// Write XML string if quantity contains numbers only.
// Blacklisting of invalid characters can be performed
// in conjunction.
if (!Pattern.matches("[0-9]+", quantity)) {
// Format violation
}
String xmlString = "<item>\n<description>Widget</description>\n" +
"<price>500</price>\n" +
"<quantity>" + quantity + "</quantity></item>";
outStream.write(xmlString.getBytes());
outStream.flush();
}
راه حل سازگار با قانون (الگوي XML)
يك مكانيزم عمومي تر براي بررسي كردن تزريق XML، استفاده از يك تعريف نوع پرونده (DTD) يا الگو است. الگو بايد به صورت مشخص تعريف شده باشد تا از تشخيص اشتباهي تزريق ها به عنوان XML هاي معتبر جلوگيري به عمل آورد. در اينجا يك الگوي مناسب براي اعتبار سنجي XML ما آورده شده است.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="item">
<xs:complexType>
<xs:sequence>
<xs:element name="description" type="xs:string"/>
<xs:element name="price" type="xs:decimal"/>
<xs:element name="quantity" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
اين الگو از طريق فايل schema.xsd قابل دسترسي است. راه حل سازگار با قانون از اين الگو براي ممانعت از موفقيت تزريق XML استفاده مي كند. همچنين براي جلوگيري از حملات XXE از كلاس CustomResolverاستفاده مي نمايد. اين كلاس به همراه حملات XXE در مثال هاي بعدي توضيح داده شده اند.
private void createXMLStream(BufferedOutputStream outStream,
String quantity) throws IOException {
String xmlString;
xmlString = "<item>\n<description>Widget</description>\n" +
"<price>500.0</price>\n" +
"<quantity>" + quantity + "</quantity></item>";
InputSource xmlStream = new InputSource(
new StringReader(xmlString)
);
// Build a validating SAX parser using our schema
SchemaFactory sf
= SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
DefaultHandler defHandler = new DefaultHandler() {
public void warning(SAXParseException s)
throws SAXParseException {throw s;}
public void error(SAXParseException s)
throws SAXParseException {throw s;}
public void fatalError(SAXParseException s)
throws SAXParseException {throw s;}
};
StreamSource ss = new StreamSource(new File("schema.xsd"));
try {
Schema schema = sf.newSchema(ss);
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setSchema(schema);
SAXParser saxParser = spf.newSAXParser();
// To set the custom entity resolver,
// an XML reader needs to be created
XMLReader reader = saxParser.getXMLReader();
reader.setEntityResolver(new CustomResolver());
saxParser.parse(xmlStream, defHandler);
} catch (ParserConfigurationException x) {
throw new IOException("Unable to validate XML", x);
} catch (SAXException x) {
throw new IOException("Invalid quantity", x);
}
// Our XML is valid, proceed
outStream.write(xmlString.getBytes());
outStream.flush();
}
استفاده از DTD براي اعتبارسنجي XML زماني مفيد است كه XML از طريق يك ورودي پاكسازي نشده بارگذاري شود. در صورتي كه رشته XML هنوز ساخته نشده است، بهتر است كه ابتدا داده هاي ورودي پاكسازي شده و سپس رشته XML ساخته شود.
حملات موجوديت خارجي XML (XEE)
يك فايل XML مي تواند به صورت پويا از بلوك هاي منطقي كوچكتري با نام entities يا موجوديت ساخته شود. موجوديت مي تواند داخلي، خارجي يا مبتني بر پارامتر باشد. موجوديت هاي خارجي اجازه ورود داده هاي XML از فايل هاي خارجي را مي دهند.
يك مهاجم مي تواند منجر به انكار سرويس يا از كار افتادن برنامه از طريق دستكاري URI موجوديت براي ارجاع دادن به فايل هاي موجود بر روي سيستم محلي شود. براي مثال /dev/randomيا/dev/ttyرا به عنوان يك URI ورودي وارد كند. اين موضوع موجب از كار افتادن يا بلوكه كردن برنامه مي شود. به اين حمله يك حمله موجوديت خارجي XML يا XEE مي گويند.
يك نمونه ناسازگار با قانون
اين نمونه ناسازگار با قانون سعي در تجزيه فايل evil.xml، گزارش خطاها و خروج دارد. به علاوه تجزيه گر SAX يا DOM سعي در دسترسي به URLي كه توسط ويژگي system مشخص شده است، دارند. اين بدين معني است كه آنها سعي در خواندن محتويات فايل محلي در آدرس /dev/tty را دارند.
مهاجم مي تواند با استفاده از اين فايل XML خرابكار منجر به از كار افتادن برنامه شود.
class XXE {
private static void receiveXMLStream(InputStream inStream,
DefaultHandler defaultHandler)
throws ParserConfigurationException, SAXException, IOException {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
saxParser.parse(inStream, defaultHandler);
}
public static void main(String[] args)
throws ParserConfigurationException, SAXException, IOException {
receiveXMLStream(new FileInputStream("evil.xml"),
new DefaultHandler());
}
}
اين برنامه مي تواند به عنوان هدف يك حمله XXE قرار بگيرد اگر فايل evil.xml حاوي محتويات زير باشد:
<?xml version="1.0"?>
<!DOCTYPE foo SYSTEM "file:/dev/tty">
<foo>bar</foo>
راه حل هاي سازگار با قانون (EntityResolver)
اين راه حل سازگار با قانون يك كلاس CustomResolver را تعريف مي كند كه واسط org.xml.sax.EntityResolver را تعريف مي كند. اين واسط برنامه كاربردي SAX را طوري تغيير مي دهد كه بتواند موجوديت هاي خارجي را مديريت نمايد. تابع setEntityResolver() نمونه را با درايور متناسب SAX ثبت مي نمايد.
در زير يك نمونه از پاكسازي از طريق كامپوننت نشان داده شده است.
class CustomResolver implements EntityResolver {
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
// Check for known good entities
String entityPath = "/home/username/java/xxe/file";
if (systemId.equals(entityPath)) {
System.out.println("Resolving entity: " + publicId +
" " + systemId);
return new InputSource(entityPath);
} else {
return new InputSource(); // Disallow unknown entities
// by returning a blank path
}
}
}
class XXE {
private static void receiveXMLStream(InputStream inStream,
DefaultHandler defaultHandler)
throws ParserConfigurationException, SAXException, IOException {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
// To set the entity resolver, an XML reader needs to be created
XMLReader reader = saxParser.getXMLReader();
reader.setEntityResolver(new CustomResolver());
reader.setContentHandler(defaultHandler);
InputSource is = new InputSource(inStream);
reader.parse(is);
}
public static void main(String[] args)
throws ParserConfigurationException, SAXException, IOException {
receiveXMLStream(new FileInputStream("evil.xml"),
new DefaultHandler());
}
}
ارزيابي خطر
شكست در پاكسازي ورودي هاي كاربر قبل از پردازش يا ذخيره داده ها منجر به حملات تزريق مي شود.
تشخيص اتوماتيك

نظرات

بدون نظر
شما برای نظر دادن باید وارد شوید

نوشته

 
تاریخ ایجاد: 18 مرداد 1393

دسته‌ها

امتیاز

امتیاز شما
تعداد امتیازها: 0