Wednesday, March 30, 2016

AngularJS EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval'

Following angular documentation for ngCsp looks like just by using the directive is not enough to avoid errors if you use inline scripts. Even after following the guidelines we were still getting randomly the below errors causing angular to stop working and consequently blank content. The reason why it was random was that we had inline javascript coming up randomly in the page:
angular.js:13424 EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "default-src 'self' 'unsafe-inline'". at Function.jQuery.extend.globalEval (jquery.js:343) at domManip (jquery.js:5290) at jQuery.fn.extend.after (jquery.js:5456) at domInsert (angular.js:5189) at Object.$provide.$get.$$animateQueue.enter (angular.js:5352) at angular.js:25332 at $$sanitizeUriProvider.$get.node (angular.js:8212) at angular.js:8551 at boundTranscludeFn (angular.js:8350) at controllersBoundTransclude (angular.js:9072)
Inspecting the jquery code it is clear that eval is used:
globalEval: function( code ) {
  var script,
   indirect = eval;

  code = jQuery.trim( code );

  if ( code ) {

   // If the code includes a valid, prologue position
   // strict mode pragma, execute code by injecting a
   // script tag into the document.
   if ( code.indexOf( "use strict" ) === 1 ) {
    script = document.createElement( "script" );
    script.text = code;
    document.head.appendChild( script ).parentNode.removeChild( script );
   } else {

    // Otherwise, avoid the DOM node creation, insertion
    // and removal by using an indirect global eval

    indirect( code );
   }
  }
 }
When angular finds inline scripts it calls the jQuery after() which triggers the globalEval()
      afterElement ? afterElement.after(element) : parentElement.prepend(element);
Clearly a quick way to identify the culprit is just looking into the html content for embedded scripts. In our case Google mod-pagespeed for apache inserted an embedded script tag as shown below:

If the scripts are below an angular directive as in the below example then you will get the error:
<!DOCTYPE html>
<html lang="en" ng-app  ng-csp>
  <head>
    <script type="text/javascript" charset="utf-8" src="jquery.js"></script>
    <script type="text/javascript" charset="utf-8" src="angular.js"></script>
  </head>
  <body>
    <div ng-if="true">
      <script>console.log('foo');</script>
    </div>
  </body>
</html>
If you can live without it then you can remove the script like we did with mod-pagespeed. If not, you will need to include your javascript code from an external source file or avoid loading jquery before angular which will limit what you can do with for example angular.element.

I think Angular should probably just detect if ng-csp is being used to avoid executing inline scripts in such case. It could also come up with a non eval way if there is still a need to run inline scripts just as it does with the "Angular's built-in subset of jQuery, called 'jQuery lite' or jqLite". At a minimum the documentation should state that currently the ng-csp directive will not work if at least if there is inline javascript inside the ng-if directive. This is a problem even if the server sends unsafe-inline like in:
 'Content-Security-Policy:default-src 'self' 'unsafe-inline'"
I submitted this issue as a potential bug for consideration.

Disabling impossible. Removing/Uninstalling mod-pagespeed

The below alone will disable Google mod-pagespeed apache module only temporarily:
sudo a2dismod pagespeed
sudo apachectl configtest
sudo apachectl graceful
For some reason we have seen it enabled back sometime after we run the above. You will need to actually uninstall it. Here is how if you installed it from the debian package in Ubuntu:
sudo sh -c \
  'dpkg -r mod-pagespeed-stable \
  && rm -f /etc/apache2/mods-available/pagespeed* \
  && service apache2 restart'

Thursday, March 17, 2016

svn: E155021: This client is too old to work with the working copy at - Finding the executable path in MAC OS X

Got this error ON MAC OS X but you believe you have available the right version?
svn: E155021: This client is too old to work with the working copy at
First look at how many svn
$ which -a svn
/usr/local/bin/svn
/usr/bin/svn
/usr/local/bin/svn
Look at the output for each of the output using the --version flag. You might notice that the default which output is not the same as the default command output:
$ command -v svn
/usr/bin/svn
$ which svn
/usr/local/bin/svn
You might be tempted to update some symlinks or your PATH variable but before doing so try from a new console, it might be just that you are hitting a console open before you installed the latest version.

Thursday, March 03, 2016

Web Application Firewall in Ubuntu with Apache and ModSecurity

Here is a recipe to install and configure ModSecurity (mod_security) tested in Ubuntu 14.04 Apache.

Note that besides copying setup files we edit inline modsecurity.conf to make sure SecRuleEngine is set to On instead of DetectionOnly (switch between them to activate the rules or just get logging information) and to make sure SecAuditLogRelevantStatus is set to "^$" instead of "^(?:5|4(?!04))" (switch between them to get log entries when the application returns 4xx or 5xx status codes or not log them at all)

This recipe will activate sql and command injection protection rules. There are several other core rules you can add just by copying them to /etc/modsecurity and restarting the server after. There are base_rules, experimental_rules and optional_rules distributed in the ModSecurity project.

To test the effectiveness of sql injection protection do not activate the rule (remove the specific crs file from the /etc/modsecurity directory), restart the server and try the below request. Apache will pass it request to your application as usual
https://sample.com/foo?bar=%27%20or%20true%20--
Now activate the rule (put the specific crs file in the /etc/modsecurity directory), restart the server and try the same request. You receive a Forbidden status code (403). From logs (/var/log/modsec_audit.log) you can read:
Message: Access denied with code 403 (phase 2). Pattern match "(^[\"'`\xc2\xb4\xe2\x80\x99\xe2\x80\x98;]+|[\"'`\xc2\xb4\xe2\x80\x99\xe2\x80\x98;]+$)" at ARGS:a. [file "/etc/modsecurity/modsecurity_crs_41_sql_injection_attacks.conf"] [line "64"] [id "981318"] [rev "2"] [msg "SQL Injection Attack: Common Injection Testing Detected"] [data "Matched Data: ' found within ARGS:a: ' or true --"] [severity "CRITICAL"] [ver "OWASP_CRS/2.2.8"] [maturity "9"] [accuracy "8"] [tag "OWASP_CRS/WEB_ATTACK/SQL_INJECTION"] [tag "WASCTC/WASC-19"] [tag "OWASP_TOP_10/A1"] [tag "OWASP_AppSensor/CIE1"] [tag "PCI/6.5.2"] Action: Intercepted (phase 2)
The recipe also activates command injection which you can test as described above using the below url:
https://sample.com/foo?bar=curl
This is a fairly simple setup which I would consider basic to secure any production web application.

You might need to add exclusions for certain non compliant and existent URLs. Since developers could take take a while to fix several existent issues and you do not want to delay the Firewall protection here are some guidelines to smooth the installation and produce your MMF ASAP.

  • Set 'SecRuleEngine DetectionOnly' so that you can compile the current problems from the log file:
    sudo sed -i  's/^SecRuleEngine.*/SecRuleEngine DetectionOnly/' /etc/modsecurity/modsecurity.conf && sudo apachectl graceful
    
  • Find the modsecurity rule id for issues so far:
    cat /var/log/apache2/yourlogname.log|grep ModSecurity|grep -o 'id "[0-9]*"'|sort|uniq
    
  • Look into each error to look into URLs needing exceptions and what it is all about. For example for id 981240:
    cat /var/log/apache2/yourlogname.log | grep ModSecurity | grep 981240
    
    Also look into the definitive modsecurity log to confirm if in doubt:
    sudo less /var/log/modsec_audit.log 
    
  • Start adding your own rules. Note that I start at rule 1 as per the documentation and I put all of them in a custom.conf file:
    # Using 25 MB for upload limit
    SecResponseBodyLimit 26214400
    # Exceptions for URLs that violate PCRE limits, dangerous characters accepted and parameters too long
    SecRule REQUEST_URI "@contains /path/containing/service/accepting/long/parameters/content/and/literal/code/and/others "phase:1,t:none,pass,id:'1',nolog,ctl:ruleRemoveById=959070,ctl:ruleRemoveById=960024,ctl:ruleRemoveById=981173,ctl:ruleRemoveById=950901,ctl:ruleRemoveById=981231,ctl:ruleRemoveById=981240,ctl:ruleRemoveById=981243,ctl:ruleRemoveById=981245,ctl:ruleRemoveById=981318"
    
  • Sometimes you need to skip modecurity rules for a specific URI, for example:
    SecRule REQUEST_BASENAME "@contains blogs" "id:1,ctl:ruleEngine=Off"
    
  • Once you get no alerts in your integration environment where surely you constantly run automated e2e tests then you can set 'SecRuleEngine On' to enable the APP FW:
    sudo sed -i  's/^SecRuleEngine.*/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf &&  sudo apachectl graceful
    

Followers