7 Mayıs 2013 Salı

JSF ve HTML Escape Problemi, Çözümü

JSF teknolojisi, web uygulamaları geliştirirken standart olarak yazılımcının uygulaması gereken bir çok güvenlik açığını kendisi gidermektedir. Bunların en önemlilerinden birisi de XSS'i engellemek için render edilen HTML'de bulunan ve atak yapmaya müsait karakterleri escape etmesidir. Örneğin ">" şeklinde yazılan bir yazı, kaynak kodunda ">" şeklinde gözükecektir. Bu özellik güvenlik açısından kolaylık sağlasa da bir takım kısıtlamalar da getirmektedir. Örneğin, yazılımcının kendisinin, xhtml içerisine yazacağı javascript ya da benzeri kod blokları, JSF'in bu özelliği sebebi ile ya compile olmaz, ya da ekranda sorunlu bir şekilde render edilir.

Bu problemin çözümü ise <h:outputText> kullanmaktır. Bu tag ile, JSF'in default davranışını bypass edebiliriz. Örneğin basit bir Javascript tagi kullanalım:
<script>alert('Test');</script>
Bu kod bloğunu direkt olarak xhtml içerisine yazarsak &lt;script&gt;alert('Test');&lt;/script&gt; gibi bir görüntü ile karşılaşırız ya da IDE'miz bu kodu derlemez, hata verir. Bu kodu önyüze taşımak için:
<h:outputText value="&lt;script&gt;alert('Test');&lt;/script&gt;" escape="false" />
şeklinde bir kullanımda bulunmalıyız. Burada, h:outputText içerisindeki değerin escape="false" ile escape edilmemesini sağlıyoruz. Burada value'yu bu şekilde vermek yerine normal bir şekilde yazarak bir String halinde tutup: <h:outputText value="#{fooController.myScript}" escape="false" /> şeklinde de kullanabilirsiniz.

Görüldüğü üzere yöntem oldukça basit. Fakat benim başıma gelen bir problem, bu şekilde bir çözüme gitmeyi engelledi ne yazık ki. Sorun şu şekilde; Internet Explorer versiyonlarına göre farklı CSS dosyaları kullanmak için html taginin başına:
"<!--[if lt IE 7]> <html lang=\"en-us\" class=\"no-js ie6\" xmlns:h="http://java.sun.com/jsf/html"> <![endif]-->..." 
tarzı kodlar yazarız. Bu kodları, yukarıda bahsettiğim şekilde escape etmek ne yazık ki mümkün değil çünkü kullandığımız <h:outputText>'in dahil olduğu "http://java.sun.com/jsf/html" namespace'ini, henüz tanımlamadan bu tagi kullanmak istiyoruz ki bu da mümkün değil. Burada da imdadımıza <f:view> tagi geliyor. <f:view> taginin içerisine namespace'lerimizi tanımladıktan sonra bütün içeriğimizi (<html> tagi vs. de dahil), <f:view> içerisine koyuyoruz. Böylece içeride <h:outputText>'i kullanabilir duruma geliyoruz ve sorunumuz çözülmüş oluyor. Daha anlaşılır olması için:

Sorun: Aşağıdaki kod bloğunu escape etmeden ön tarafa taşımak
<!--[if lt IE 7]>          <html lang="en-us" class="no-js ie6"> <![endif]-->
<!--[if IE 7]>             <html lang="en-us" class="no-js ie7"> <![endif]-->
<!--[if IE 8]>             <html lang="en-us" class="no-js ie8"> <![endif]-->
<!--[if gt IE 8]><!--> <html lang="en-us" class="no-js" xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core"> <!--<![endif]-->
Çözüm: Kod bloğunu <f:view> içerisine alıp namespace'leri buraya taşımak
@Controller("fooController")
FooController{
   public String myUnescapedString =
 
                    "<!--[if lt IE 7]><html lang=\"en-us\" class=\"no-js ie6\"> <![endif]-->\n" +
                    "<!--[if IE 7]><html lang=\"en-us\" class=\"no-js ie7\"> <![endif]-->\n" +
                    "<!--[if IE 8]><html lang=\"en-us\" class=\"no-js ie8\"> <![endif]-->\n" +
                    "<!--[if gt IE 8]><!--> <html lang=\"en-us\" class=\"no-js\"> <!--<![endif]-->";
}
<f:view contentType="text/html"
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:f="http://java.sun.com/jsf/core">
<h:outputText value="#{fooController.myUnescapedString}" escape="false"/>
</f:view>
( jsf, html, escape, h:outputText, f:view, unescape, xss )
Kaynak: http://stackoverflow.com/questions/10616944/jsf-2-1-ie-conditional-comments

Hiç yorum yok:

Yorum Gönder