BookmarkSubscribeRSS Feed

All about CORS and CSRF for developing web applications with the SAS Visual Analytics SDK

Started ‎01-20-2022 by
Modified ‎03-01-2023 by
Views 8,519

Have you ever wondered how to configure Cross-Origin Resource Sharing (CORS) and Cross-Site Request Forgery (CSRF) settings so that web applications developed with the SAS Visual Analytics SDK work properly in SAS Viya?

 

Me either, but it turns out CORS and CSRF are actually quite useful web security concepts to understand. If you are an administrator you may need to configure settings for them in SAS Environment Manager, or in a script, so that your web applications built using the Visual Analytics SDK | SAS and running on other servers, or using content from other servers, work and are not blocked by the users' browser.

 

In this article I'll explain what CORS and CSRF are, why they matter, and how to configure SAS's settings for them in SAS Environment Manager.

 

Background: web applications that work with SAS Viya

 

There are two ways you can make web applications that use SAS Viya: you can include what are effectively iFrames in a SAS Visual Analytics report tab that show (often interactive) content from other web servers or web applications. You can also embed SAS Visual Analytics content within custom ​web pages and web apps. You might even do both at the same time in the same report. As a web application developer or administrator, the reason you need to know about CORS and CSRF is that having your own trusted web application server (e.g. SAS Viya) deliver a page to your browser whose content comes at least in part from a completely different and perhaps untrusted web application server provides a rather obvious opportunity for a security vulnerability. Your browser will rightly refuse to load the untrusted content, unless you take steps in your web application server's configuration (i.e. in SAS Environment Manager) to define a rule to allow it.  

 

What are CORS and CSRF?

 

Cross-Origin Resource Sharing (CORS, see developer.sas.com | CORS in SAS REST APIs) is where JavaScript running on a web page served by one web server uses a REST API or loads content from a different server. In this context, a different server means at least one of: a different domain (i.e. hostname), protocol (e.g. http or https) or port (e.g. 80, 443 or something else). If you have a Visual Analytics report which contains an iFrame showing content from a web application hosted anywhere else but in the same SAS Viya Kubernetes cluster, your report likely uses Cross-Origin Resource Sharing. Similarly, if you embed an element of a SAS Visual Analytics report in your own web application.

 

CORS is open to being exploited to serve malicious content inside a web page on an otherwise trusted server. Because of this, web browsers refuse to allow CORS unless, in simple terms, the first web server specifically says the second web server's content (specified by protocol, domain, and port) is allowed.

 

A Cross-Site Request Forgery is slightly harder to explain, so I'm going to quote the excellent definition from this page: What is CSRF (Cross-site request forgery)?.

 

Cross-site request forgery (also known as CSRF) is a web security vulnerability that allows an attacker to induce users to perform actions that they do not intend to perform. It allows an attacker to partly circumvent the same origin policy, which is designed to prevent different websites from interfering with each other.

 

In the context of SAS Viya, a CSRF-induced action could potentially be to retrieve sensitive data and send it to a third party, or to change the data the user sees on screen etc., using the user's authentication token but without their knowledge. Your browser protects against CSRF, but we need to define some exceptions to the CSRF prevention rules in SAS Viya, in order to allow the Visual Analytics SDK | SAS work properly. See also CSRF in SAS Viya Setup · SAS® Visual Analytics SDK.

 

In the development phase, you may run your web application on a laptop, and access the web application at the 'localhost' hostname. But SAS Viya is likely to be running in a Kubernetes cluster elsewhere. Here, you need to configure the CORS and CSRF in SAS Viya to allow integration with your local web application server running on 'localhost'.

 

In production, that would be inadvisable! Here, you host your web application on a proper web application server, which could potentially be configured to be hosted from the same domain name as SAS Viya. This may take less complex settings in the CORS and CSRF configuration for SAS Viya. The closer to SAS Viya the web application server is, the easier it is to configure the CORS and CSRF settings.  

 

Example CORS and CSRF configuration

 

CORS

In Viya 2020.1 and later, CORS and CSRF configuration settings are found in SAS Environment Manager > Configuration. In the 'All Services' view, find and select 'Global'. On the right-hand side, collapse all to see the list of all Global configuration instances:

 

ds_1_EV-Configuration-Page-showing-Global-Configuration-Instances-1024x504.png

Select any image to see a larger version.
Mobile users: To view the images, select the "Full" version at the bottom of the page.

 

If you expand the configuration instance for CORS (sas.commons.web.security.cors), and scroll down to see the allowedOrigins, you can see that several sites have been added to origins from which Cross Origin Resource Sharing is allowed:

 

Now, because these entries are real and this article is (or will soon be) public, I've blurred them out in the screenshot:

 

ds_2_CORS-config-with-blurred-hostnames-1024x681.png

 

Here are illustrative examples that are in the same form as the real ones: https://localhost:3000,https://internal-alias1.sas.com,https://internal-alias2.sas.com,https://inter...

 

Notice that the format is a comma-separated list of strings, each of which has a protocol (e.g. http:// or https://), a hostname, alias, or domain (e.g. localhost, internal-alias1.sas.com) and where necessary, a port number (e.g. :3000). Most of these entries do not specify a port number, which is because they are using the default ports of 80 for HTTP and 443 for HTTPS.

 

Notice also that there are no wildcards in the allowedOrigins string, but there are asterisk wildcards for allowedHeaders and allowedMethods, meaning any header or method is allowed. There are a couple of other settings in the configuration instance that I think are default and not worth mentioning. According to the documentation (find it in the SAS® Viya® Administration guide for 2021.2.2, under Configuring > Configuration Reference > Configuration Properties: Reference (System) > Security > sas.commons.web.security.cors), wildcards ('*') can be used and appear to be the default for allowedHeaders and allowedMethods, but you cannot use wildcards for allowedOrigins. You have to list each origin out in full, separately, like the example we already saw above.  

 

CSRF

The configuration instance for CSRF (sas.commons.web.security.csrf) is rather simpler, and you can use a regular expression to define the general pattern of sites that you will allow to run actions in your SAS Viya web application. Here's what that configuration instance looks like in our environment:

 

ds_3_CSRF-config-2-1024x681.png

 

Really the only significant value is for allowedURIs, where our string containing our list of comma-separated regular expressions is:

 

(.+\.)+.+\.sas\.com,.*

 

You don't have to copy these of course, but I think it is helpful to explain what ours does. Our regular expression list contains two regular expressions:

 

  • The first one, (.+\.)+.+\.sas\.com, is what we might use in a production Viya deployment. It matches URIs in the form a.b.sas.com, or a.b.c.sas.com, or a.b.c.d.sas.com etc. It would not match a.sas.com, or a.example.com. Notice that these expressions do NOT need to match the entire URI, they only need to match a part of the URI to allow a request.
  • The second regular expression, .*, is useful for development and testing as it matches absolutely any URI!

 

In a production environment, we would not include the second regular expression. We might also spend additional time considering the strictness of the first expression. But we decided this was fine for matching hostnames like localhost for our development and student exercise needs in this teaching/lab environment.  

 

Scripting configuration of CORS and CSRF

Here is an example of a bash script you might run to configure CORS and CSRF as described above. It is a modified version of a real script which runs as part of a much larger set of scripts, so it omits things like setting up our pyviyatools project in ~/pyviyatools, and setting up the certificates and a .authinfo file to allow authentication to the sas-viya CLI using the loginviauthinfo.py tool. We pass in a namespace when running this script as an argument ($1 which becomes $NS). Our deployment files are in the current user's ~/project/deploy directory, under a subdirectory named for the Viya namespace. I've used the fictitious hostnames for CORS allowed origins in this script too, as I did in the explanation above.  

 

#!/bin/bash
######################################################################################
#
#   configure CORS/CSRF
#   configure Compute autoexec
#
######################################################################################
NS=$1
export PATH=$PATH:~/pyviyatools:/opt/sas/viya/home/bin

# steps for standard url to shared environment
mkdir ~/project/deploy/${NS}/site-config/JSON
tee  ~/project/deploy/${NS}/site-config/JSON/LogonCORS.json > /dev/null << EOF
{
  "name": "addLogonSecurity",
  "items": [
    {
      "version": 1,
      "metadata": {
        "isDefault": false,
        "mediaType": "application/vnd.sas.configuration.config.sas.commons.web.security.cors+json;version=2"
      },
      "allowedOrigins": "https://localhost:3000,https://internal-alias1.sas.com,https://internal-alias2.sas.com,https://internal-alias3.sas.com,https://internal-alias4.sas.com",
      "allowedHeaders": "*",
      "allowedMethods": "*",
      "allowCredentials": true
    }
  ]
}
EOF

# Create the CSRF JSON file to allows all .sas.com URIs.  The quadruple backslash,
# \\\\, is required so that it is correct in the configuration.  Ultimately it
# should look like this:  "(.+\.)+.+\.sas\.com"
tee  ~/project/deploy/${NS}/site-config/JSON/LogonCSRF.json > /dev/null << EOF
{
  "name": "addCSRF",
  "items": [
    {
      "version": 1,
      "metadata": {
        "isDefault": false,
        "mediaType": "application/vnd.sas.configuration.config.sas.commons.web.security.csrf+json;version=2"
      },
      "allowedUris": "(.+\\\\.)+.+\\\\.sas\\\\.com",
      "failIfNoHeaders": false
    }
  ]
}
EOF

# Login
loginviauthinfo.py -f ~/.authinfo_sasadm

# Update configuration for CORS and CSRF
sas-viya configuration configurations create --file ~/project/deploy/${NS}/site-config/JSON/LogonCORS.json
sas-viya configuration configurations create --file ~/project/deploy/${NS}/site-config/JSON/LogonCSRF.json

# Restart SASLogon
logit "Restart SASLogon to pickup CORS/CSRF changes"
kubectl -n ${NS} delete pod --selector="app.kubernetes.io/name=sas-logon-app"
time kubectl -n ${NS} wait --for=condition=Ready pod -l app=sas-logon-app --timeout=900s

 

You will need to adapt that script to work in your environment, but I hope this gives a gist of what you could do to script the setup, if you wished to.  

 

Bonus: Configure Cross-Site Cookies

[Added 28 Feb 2023] My colleague Xavier worked with a customer recently to set up SAS Job Execution for use in a SAS Visual Analytics report, and they noticed that they also had to modify a setting for Cross-Site Cookies, setting the sameSite option to None in the sas.commons.web.security.cookies configuration instance to get authentication working properly between the two applications.

The details are explained in SAS Viya Setup · SAS® Visual Analytics SDK, under 'Cross-Site Cookies'. This page also has a link to Configure the SameSite Attribute in the SAS Viya Platform Administration guide, which describes the different values to which you can set the sameSite setting.

Xavier and his customer found that if you don't set this sameSite option to None, the session cookie is not passed along with the request to SAS Job Execution, and as a result requests to SASJobExecution fail to authenticate. Setting it as documented above was the solution.

 

Acknowledgements and further reading

My sincere thanks to my colleagues @XavierBizoux and @GillesChrzaszcz for their contributions to this article. Xavier suggested writing it and provided very patient and detailed explanations of how he had set it up for his web application development work. Gilles wrote the original versions of the script I've approximately reproduced above.

 

These settings might be useful if you are following Xavier's Develop web applications series:

To learn how to add a CAS server, see SAS Help Center: SAS Cloud Analytic Services: How To > Add a CAS Server. Or more generally, to learn about tasks like adding a backup controller, adding a worker node etc., see the other How To (Tasks) sections here.

 

Find more articles from SAS Global Enablement and Learning here.

Version history
Last update:
‎03-01-2023 04:45 AM
Updated by:
Contributors

sas-innovate-2024.png

Available on demand!

Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.

 

Register now!

Free course: Data Literacy Essentials

Data Literacy is for all, even absolute beginners. Jump on board with this free e-learning  and boost your career prospects.

Get Started

Article Tags