59

I have a web application built on JSF with MySQL as DB. I have already implemented the code to prevent CSRF in my application.

Now since my underlying framework is JSF, I guess I don't have to handle XSS attack as it is already handled by UIComponent. I am not using any JavaScript in any of the view pages. Even if I use do I really need to implement code to prevent XSS attacks?

For DB we are using prepared statements and stored procedures in all DB interactions.

Is there anything else needs to be handled for preventing these 3 common attacks? I have already been through the OWASP site and their cheat sheets.

Do I need to take care of any other potential attack vectors?

AngelsandDemons
  • 2,823
  • 13
  • 47
  • 70

3 Answers3

122

XSS

JSF is designed to have builtin XSS prevention. You can safely redisplay all user-controlled input (request headers (including cookies!), request parameters (also the ones which are saved in DB!) and request bodies (uploaded text files, etc)) using any JSF component.

<h:outputText value="#{user.name}" />
<h:outputText value="#{user.name}" escape="true" />
<h:inputText value="#{user.name}" />
etc...

Note that when you're using JSF 2.0 on Facelets, then you can use EL in template text like so:

<p>Welcome, #{user.name}</p>

This will also implicitly be escaped. You don't necessarily need <h:outputText> here.

Only when you're explicitly unescaping user-controlled input using escape="false":

<h:outputText value="#{user.name}" escape="false" />

then you've a potential XSS attack hole!

If you'd like to redisplay user-controlled input as HTML wherein you would like to allow only a specific subset of HTML tags like <b>, <i>, <u>, etc, then you need to sanitize the input by a whitelist. The HTML parser Jsoup is very helpful in this.

itemLabelEscaped bug in Mojarra < 2.2.6

Older Mojarra versions before 2.2.6 had the bug wherein <f:selectItems itemLabel> incorrectly renders the label unescaped when provided a List<T> via <f:selectItems var> instead of List<SelectItem> or SelectItem[] as value (issue 3143). In other words, if you're redisplaying user-controlled data as item labels via a List<T>, then you've a potential XSS hole. If upgrading to at least Mojarra 2.2.6 is not an option, then you need to explicitly set itemLabelEscaped attribute to true to prevent that.

<f:selectItems value="#{bean.entities}" var="entity" itemValue="#{entity}"
    itemLabel="#{entity.someUserControlledProperty}" itemLabelEscaped="true" />

CSRF

JSF 2.x has already builtin CSRF prevention in flavor of javax.faces.ViewState hidden field in the form when using server side state saving. In JSF 1.x this value was namely pretty weak and too easy predictable (it was actually never intended as CSRF prevention). In JSF 2.0 this has been improved by using a long and strong autogenerated value instead of a rather predictable sequence value and thus making it a robust CSRF prevention.

In JSF 2.2 this is even be further improved by making it a required part of the JSF specification, along with a configurable AES key to encrypt the client side state, in case client side state saving is enabled. See also JSF spec issue 869 and Reusing ViewState value in other session (CSRF). New in JSF 2.2 is CSRF protection on GET requests by <protected-views>.

Only when you're using stateless views as in <f:view transient="true">, or there's somewhere a XSS attack hole in the application, then you've a potential CSRF attack hole.


SQL injection

This is not JSF's responsibility. How to prevent this depends on the persistence API you're using (raw JDBC, modern JPA or good ol' Hibernate), but all boils down that you should never concatenate user-controlled input into SQL strings like so

String sql = "SELECT * FROM user WHERE username = '" + username + "' AND password = md5(" + password + ")";
String jpql = "SELECT u FROM User u WHERE u.username = '" + username + "' AND u.password = md5('" + password + "')";

Imagine what would happen if the enduser chooses the following name:

x'; DROP TABLE user; --

You should always use parameterized queries where applicable.

String sql = "SELECT * FROM user WHERE username = ? AND password = md5(?)";
String jpql = "SELECT u FROM User u WHERE u.username = ?1 AND u.password = md5(?2)";

In plain JDBC you need to use PreparedStatement to fill the parameter values and in JPA (and Hibernate), the Query object offers setters for this as well.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 5
    I'd add that contrary to popular believe, using stored procedures does **not** automatically save you from SQL injection attacks: I've seen stored procedures create SQL statements by concatenation and **that** is *equally vulnerable* to SQL injection! It's the same way that using PreparedStatements doesn't automatically save your from SQL injection attacks, if you're using them wrong! – Joachim Sauer Oct 11 '11 at 12:17
  • 1
    @BalusC Well I cannot thank you enough for this awesome explanation..But I have some doubts. In my GUI, I use for displaying on the GUI..Now this is a potential XSS Attack.How do I avoid it.??. Secondly, I am stll using JSF 1.2 and so how do I handle CSRF then?.I used WebScrarab tool to intercept Http Request and modify the value and it indeed was successful.Does it mean that the application is prone to Attack.How can I avoid it. I have already handled SQL injection. Only thing to worry for me is XSS and CSRF as of now..Please help. – AngelsandDemons Oct 12 '11 at 10:32
  • @BalusC Also the explanation provided by Samuel suggest me to have a look at closure Template for sanitizing HTML input. But I have heard that closure template has serious performance issue and morever it is from Google Labs so it will be almost in Beta version hence not stable...Which one would you recommend for HTMl santizing..Jsoup or Closure..I am absolutely new to this santizing and parsing and hence I would prefer something which is easy to learn and implement. – AngelsandDemons Oct 12 '11 at 10:58
  • 3
    As to XSS, just remove `escape="false"`. Or if you want to allow certain HTML, then use Jsoup. You just need to do `String safe = Jsoup.clean(unsafe, Whitelist.basic());`. See also [this guide](http://jsoup.org/cookbook/cleaning-html/whitelist-sanitizer). You can do this directly before saving input in DB. As to CSRF prevention in JSF 1.x, you should maintain a session based anti-CSRF token in the form (basically, a hidden input field with a long/autogenerated/unpredictable value). Seam framework has similar component ``: http://seamframework.org/Documentation/CrossSiteRequestForgery – BalusC Oct 12 '11 at 12:40
  • @BalusC if you will have a look on the [OWASP Dokument about ORM Injection](https://www.owasp.org/index.php?title=Interpreter_Injection#ORM_Injection) you could read `the current Oracle JDBC driver escapes input for prepared statements and parameterized stored procedures.` so this means, your are safe from Injections, right? – Joergi Mar 09 '12 at 11:16
  • @BalusC can we for better security write a filter and in this use Jsoup.clean on all request parameters? i do this but it back me a `java.lang.IllegalStateException` and says `No modifications are allowed to a locked ParameterMap`. thanks for time that you spend. – Rasoul Taheri Jan 19 '14 at 09:11
  • @Rasoul: don't do it during input, but during output only. – BalusC Jan 19 '14 at 09:16
  • @BalusC can you say what i must abstain this in input? i store some data in database. and during output mean that do this work on response object parameters? thanks alot. – Rasoul Taheri Jan 19 '14 at 10:04
  • Regarding XSS and automatic escaping in JSF I'd consider it worth mentioning that there is one exception to the rule (for h:selectOneMenu components), documented here: http://stackoverflow.com/questions/15020320/jsf-selectitems-and-escaping-xss – t3chris Mar 23 '14 at 13:18
  • @BalusC, is #{user.name} escaped even if I use JSTL with Facelets? – guest Apr 03 '15 at 12:46
  • JSF 2.3 seems to have deprecated `` – Sometowngeek Apr 27 '20 at 16:51
  • @Sometowngeek: Nope. What's your source? – BalusC Apr 27 '20 at 17:04
  • My apologies... I jumped the gun when I was trying to set it in the wrong spot. I also did some looking around and the JSF 2.3 doc doesn't seem like you can find search results in the code, so I started to worry. It seems I was supposed to set it in **faces-config.xml** instead of **web.xml**. – Sometowngeek Apr 27 '20 at 18:52
  • @BalusC is the ViewState Id (server side state saving) still random enough by default in 2020? An external PenTester told us predicting could be possible ([which is also told here](https://blog.securityevaluators.com/cracking-javas-rng-for-csrf-ea9cacd231d2?gi=15ae464340a0)). He adviced us to set _org.apache.myfaces.RANDOM_KEY_IN_VIEW_STATE_SESSION_TOKEN_ to _secureRandom_. – DaniEll Nov 19 '20 at 12:07
  • @DaniEll: Completely right. But it'll only be successful if there's a successful XSS attack in order to grab the session cookie. If that isn't possible in first place then the proposed CSRF attack won't work because the view state is in turn saved in session. But nonetheless .. When there's in first place already a successful XSS attack, then you have way much bigger problems than only this way of CSRF .. – BalusC Nov 19 '20 at 12:24
  • @BalusC it could also be a classic CSRF with a POST from another domain (clickjacking). When the ViewState is guessed correctly, the request is going to be processed in context of my session. – DaniEll Nov 19 '20 at 13:20
8

I am not using any JavaScript in any of the view pages. Even if I use do I really need to implement code to bypass XSS Attack.

You can be vulnerable to XSS even if you don't use JavaScript in your pages. XSS occurs when you incorporate content controlled by an attacker without properly encoding it.

Anytime you do something like

response.write("<b>" + x + "</b>")

where an attacker can cause x to contain HTML that contains JavaScript, then you are vulnerable to XSS.

The solution is usually not to write large amounts of code. Typically the solution is to encode $x and any other values controlled by an attacker before including them in the HTML you generate.

response.write("<b>" + escapePlainTextToHtml(x) + "</b>")

Filtering or sanitizing inputs can help provide an additional layer of protection.

<shameless-plug>

You can also use a template language that encodes output automatically to protect against XSS.

Closure Template is one such option for Java.

Contextual autoescaping works by augmenting Closure Templates to properly encode each dynamic value based on the context in which it appears, thus defending against XSS vulnerabilities in values that are controlled by an attacker.

EDIT

Since you are using JSF you should read up on XSS mitigation in JSF:

Escape output text

<h:outputText/> and <h:outputLabel/> by default has the escape attribute set to True. By using this tag to display outputs, you are able to mitigate majority of the XSS vulnerability.

SeamTextParser and <s:formattedText/>

If you would like to allow users to utilise some of the basic html tags to customise their inputs, JBoss Seam provides a <s:formattedText/> tag that allows some basic html tags and styles specified by users.

Community
  • 1
  • 1
Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • @ankit, Is there a particular sentence that you find confusing? – Mike Samuel Oct 11 '11 at 06:49
  • Problem is I am using JSF and i guess just like other frameworks it automatically generates HTML..So I am still clueless about what your wrote..I also went through the closure template..It is so new to me... – AngelsandDemons Oct 11 '11 at 07:27
  • 1
    Also to add:- My GUI will not allow the user to enter angle bracket tags<>.It will fail client side validation and the request won't be processed..As I understood IF I ALLOW USER to enter HTML tags in my GUI then I need to use the closure template to ensure which all are valid tags and which all are not valid...Please do correct me if am wrong. – AngelsandDemons Oct 11 '11 at 07:31
  • @ankit, I edited to add a pointer to some best practices for XSS mitigation in JSF. – Mike Samuel Oct 11 '11 at 08:24
  • 3
    Unlike as in old fashioned JSP/Servlet, JSF has not really a concept of `response.write(foo)`. This answer is a bit confusing towards users who are new to JSF 2.x. – BalusC Oct 11 '11 at 12:03
1

When using <h:outputText escape="false"> with unescaped values (for example coming from html text editors) you're open for a nasty XSS attacks. In such cases I'm using a JSF converter which uses Jsoup to remove javascript from text leaving HTML intact. Converter can be used to sanitize user inputs as well. You can use it like this:

<h:outputText value="{bean.value}" escape="false" converter="htmlSanitizingConverter"/>

And the converter itself:

/**
 * Prevents from XSS attack if output text is not escaped.
 */
@FacesConverter("htmlSanitizingConverter")
public class HtmlSanitizingConverter implements Converter {

    private static final Whitelist JSOUP_WHITELIST = Whitelist.relaxed()
            .preserveRelativeLinks(true)
            .addAttributes(":all","style");
            /*
             Optionally - add support for hyperlinks and base64 encoded images.
            .addTags("img")
            .addAttributes("img", "height", "src", "width")
            .addAttributes("a", "href")
            .addProtocols("img", "src", "http", "https", "data");
            */

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
        return (submittedValue != null) ? Jsoup.clean(submittedValue, JSOUP_WHITELIST) : null;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return (value != null) ? Jsoup.clean(value.toString(), JSOUP_WHITELIST) : "";
    }

}

Note: When you're using JSF with PrimeFaces, beware of <p:textEditor> - older versions (prior to 6.2) by default didn't sanitize user input.

Michał Stochmal
  • 5,895
  • 4
  • 36
  • 44
  • 1
    1: individual components should not be an answer to a generic question. 2: The issue is fixed in 7.0 in that the component can be configured to do cleaning and in 7.1 it wil even be the default. – Kukeltje Sep 27 '19 at 09:10
  • @Kukeltje converter is generic solution for solving this problem regardless of used technology. I'm just pointing this PF issue because it's the most popular JSF components library and older versions of PF are still heavily used (and in most cases won't be updated due to compatibility issues). – Michał Stochmal Sep 27 '19 at 09:17
  • I'm not saying your answer is not valuable, I think it is, just that it does not directly belong here. You are allowed (and even encouraged) in Stackoverflow to create a question and answer it yourself. E.g. 'How do I prevent XSS in p:textEditor` and answer it yourself with this answer. It is seriously highly appreciated and keeps things clear, separated etc. – Kukeltje Sep 27 '19 at 09:42
  • 1
    I understand the converter is generic, but that is also the case when using a plain textarea and a custom js html editor plugin (or markdown or even when plain html is entered in a textarea). So you can make it more generic by focussing on the different ways of inputs too (in there referring to the `p:textEditor` to). Now the answer looks to focus soley on the `p:textEditor` while the solution is in the display and not the 'entering of data' (you could use a converter on the input too... Even more clean... No risks if someone forgets to apply it on the output – Kukeltje Sep 27 '19 at 09:47