Browse Source

ready for cinc

master
boB Rudis 5 years ago
parent
commit
0b3b097c55
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 1
      NAMESPACE
  2. 4
      R/as-data-frame.R
  3. 38
      R/findings.R
  4. 6
      R/parse-csp-text.R
  5. 90
      README.Rmd
  6. 164
      README.md
  7. 3
      man/csp_security_checkers.Rd
  8. 3
      man/has_csp.Rd
  9. 4
      man/parse_csp.Rd
  10. 2
      tests/test-all.R
  11. 28
      tests/testthat/test-cspy.R

1
NAMESPACE

@ -32,7 +32,6 @@ export(check_script_unsafe_eval)
export(check_script_unsafe_inline)
export(check_src_http)
export(check_wildcards)
export(ensure_csp_df)
export(fetch_csp)
export(has_csp)
export(parse_csp)

4
R/as-data-frame.R

@ -28,7 +28,9 @@ as.data.frame.csp <- function(x, row.names=NULL, optional=NULL, include_origin =
})
) -> xdf
if ((!is.na(x$origin)) && include_origin) xdf[["origin"]] <- x$origin
if (nrow(xdf) > 0) {
if ((!is.na(x$origin)) && include_origin) xdf[["origin"]] <- x$origin
}
class(xdf) <- c("tbl_df", "tbl", "data.frame")

38
R/findings.R

@ -15,17 +15,6 @@ mk_finding <- function(category, message, severity, where) {
#' @name csp_security_checkers
NULL
# Checks if passed csp allows inline scripts.
#' @rdname csp_security_checkers
#' @param csp_df Preferably a CSP data frame (made with [as.data.frame()]) but
#' can be a raw CSP object. Passing in a pre-made data frame will be faster
#' when using multiple CSP security checker functions.
#' @return a `csp_finding` or `csp_findings_list` object containing one or more `csp_finding`
#' objects. Each `csp_finding` object will have the `category`, `severity`,
#' `message` and `where` the violation(s) occurred.
#' @references [CSP With Google](https://csp.withgoogle.com/docs/index.html)
#' @export
ensure_csp_df <- function(csp_df) {
if (inherits(csp_df, "csp")) {
as.data.frame(csp_df)
@ -38,8 +27,16 @@ ensure_csp_df <- function(csp_df) {
}
}
# Checks if passed csp allows eval in scripts.
# Checks if passed csp allows inline scripts.
#' @rdname csp_security_checkers
#' @param csp_df Preferably a CSP data frame (made with [as.data.frame()]) but
#' can be a raw CSP object. Passing in a pre-made data frame will be faster
#' when using multiple CSP security checker functions.
#' @return a `csp_finding` or `csp_findings_list` object containing one or more `csp_finding`
#' objects. Each `csp_finding` object will have the `category`, `severity`,
#' `message` and `where` the violation(s) occurred.
#' @references [CSP With Google](https://csp.withgoogle.com/docs/index.html)
#' @export
check_script_unsafe_inline <- function(csp_df) {
csp_df <- ensure_csp_df(csp_df)
@ -59,7 +56,7 @@ check_script_unsafe_inline <- function(csp_df) {
}
}
# Checks if plain URL schemes (e.g. http:) are allowed in sensitive directives.
# Checks if passed csp allows unsafe eval
#' @rdname csp_security_checkers
#' @export
check_script_unsafe_eval <- function(csp_df) {
@ -83,7 +80,7 @@ check_script_unsafe_eval <- function(csp_df) {
URL_SCHEMES_CAUSING_XSS <- c("data:", "http:", "https:")
XSS_DIRECTIVES <- c("script-src", "object-src", "base-uri")
# Checks if csp contains wildcards in sensitive directives.
# Checks if plain URL schemes (e.g. http:) are allowed in sensitive directives.
#' @rdname csp_security_checkers
#' @export
check_plain_url_schemes <- function(csp_df) {
@ -102,7 +99,7 @@ check_plain_url_schemes <- function(csp_df) {
}
}
# Checks if csp contains wildcards in sensitive directives
# Checks if csp contains wildcards in sensitive directives.
#' @rdname csp_security_checkers
#' @export
check_wildcards <- function(csp_df) {
@ -201,17 +198,8 @@ check_missing_directives <- function(csp_df) {
}
script_src_missing <- FALSE
script_src <- csp_df[csp_df[["directive"]] == "script-src",]
if (nrow(script_src)) {
none <- script_src[script_src[["value"]] == "'none'",]
if (nrow(none) == 0) {
self <- script_src[script_src[["value"]] == "'self'",]
if (nrow(self) == 0) script_src_missing <- TRUE
}
} else {
script_src_missing <- TRUE
}
script_src_missing <- (nrow(script_src) == 0)
if (script_src_missing) {
findings[[length(findings)+1]] <- mk_finding(

6
R/parse-csp-text.R

@ -4,6 +4,8 @@
#' @param method method to use fetch CSP (sites may change headers returned
#' depending on the method used)
#' @export
#' @examples
#' has_csp("https://rud.is/")
has_csp <- function(URL, method = c("head", "get")) {
method <- match.arg(tolower(method), c("head", "get"))
@ -32,6 +34,8 @@ has_csp <- function(URL, method = c("head", "get")) {
#' depending on the method used)
#' @references [Content Security Policy Level 3](https://www.w3.org/TR/CSP3/)
#' @export
#' @examples
#' parse_csp("default-src: 'none'", "https://example.com")
parse_csp <- function(csp_text, origin_url) {
ParserWithLocation <- J("com.shapesecurity.salvation.ParserWithLocation")
@ -50,6 +54,8 @@ parse_csp <- function(csp_text, origin_url) {
#' @rdname parse_csp
#' @export
#' @examples
#' fetch_csp("https://rud.is/")
fetch_csp <- function(origin_url, method = c("head", "get")) {
method <- match.arg(tolower(method), c("head", "get"))

90
README.Rmd

@ -4,7 +4,7 @@ editor_options:
chunk_output_type: console
---
```{r pkg-knitr-opts, include=FALSE}
knitr$opts_chunk$set(collapse=TRUE, fig.retina=2, message=FALSE, warning=FALSE)
knitr::opts_chunk$set(collapse=TRUE, fig.retina=2, message=FALSE, warning=FALSE)
options(width=120)
```
@ -29,31 +29,44 @@ The following functions are implemented:
Core:
- `fetch_csp`: Fetch and/or parse a content security policy header value
- `parse_csp`: Fetch and/or parse a content security policy header value
- `validate_csp`: Validate a CSP
- `fetch_csp`: Fetch and/or parse a content security policy header value
- `has_csp`: Does a URL have a content security policy?
- `parse_csp`: Fetch and/or parse a content security policy header value
- `validate_csp`: Validate a CSP
- `as.data.frame.csp`: Convert a parsed CSP into a data frame of directives and values
Security/Safety Checks:
- `check_deprecated`: Tests for insecure CSP settings
- `check_ip_source`: Tests for insecure CSP settings
- `check_missing_directives`: Tests for insecure CSP settings
- `check_nonce_length`: Tests for insecure CSP settings
- `check_plain_url_schemes`: Tests for insecure CSP settings
- `check_script_unsafe_eval`: Tests for insecure CSP settings
- `check_script_unsafe_inline`: Tests for insecure CSP settings
- `check_src_http`: Tests for insecure CSP settings
- `check_wildcards`: Tests for insecure CSP settings
Testers:
- `allows_child_from_source`: Tests for what a parsed CSP allows
- `allows_connect_to`: Tests for what a parsed CSP allows
- `allows_font_from_source`: Tests for what a parsed CSP allows
- `allows_form_action`: Tests for what a parsed CSP allows
- `allows_frame_ancestor`: Tests for what a parsed CSP allows
- `allows_frame_from_source`: Tests for what a parsed CSP allows
- `allows_manifest_from_source`: Tests for what a parsed CSP allows
- `allows_media_from_source`: Tests for what a parsed CSP allows
- `allows_navigation`: Tests for what a parsed CSP allows
- `allows_object_from_source`: Tests for what a parsed CSP allows
- `allows_prefetch_from_source`: Tests for what a parsed CSP allows
- `allows_script_from_source`: Tests for what a parsed CSP allows
- `allows_script_with_nonce`: Tests for what a parsed CSP allows
- `allows_style_from_source`: Tests for what a parsed CSP allows
- `allows_style_with_nonce`: Tests for what a parsed CSP allows
- `allows_unsafe_inline_script`: Tests for what a parsed CSP allows
- `allows_unsafe_inline_style`: Tests for what a parsed CSP allows
- `allows_worker_from_source`: Tests for what a parsed CSP allows
- `as.data.frame.csp`: Convert a parsed CSP into a data frame of directives and values
- `allows_child_from_source`: Tests for what a parsed CSP allows
- `allows_connect_to`: Tests for what a parsed CSP allows
- `allows_font_from_source`: Tests for what a parsed CSP allows
- `allows_form_action`: Tests for what a parsed CSP allows
- `allows_frame_ancestor`: Tests for what a parsed CSP allows
- `allows_frame_from_source`: Tests for what a parsed CSP allows
- `allows_manifest_from_source`: Tests for what a parsed CSP allows
- `allows_media_from_source`: Tests for what a parsed CSP allows
- `allows_navigation`: Tests for what a parsed CSP allows
- `allows_object_from_source`: Tests for what a parsed CSP allows
- `allows_prefetch_from_source`: Tests for what a parsed CSP allows
- `allows_script_from_source`: Tests for what a parsed CSP allows
- `allows_script_with_nonce`: Tests for what a parsed CSP allows
- `allows_style_from_source`: Tests for what a parsed CSP allows
- `allows_style_with_nonce`: Tests for what a parsed CSP allows
- `allows_unsafe_inline_script`: Tests for what a parsed CSP allows
- `allows_unsafe_inline_style`: Tests for what a parsed CSP allows
- `allows_worker_from_source`: Tests for what a parsed CSP allows
## Installation
@ -65,12 +78,43 @@ install.packages("cspy", repos = "https://cinc.rud.is/")
```{r lib-ex}
library(cspy)
library(tibble) # for printing
# current version
packageVersion("cspy")
```
```{r one}
has_csp("https://community.rstudio.com")
csp <- fetch_csp("https://community.rstudio.com")
csp
(csp_df <- as.data.frame(csp))
allows_unsafe_inline_script(csp)
check_deprecated(csp_df)
check_ip_source(csp_df)
check_missing_directives(csp_df)
check_nonce_length(csp_df)
check_plain_url_schemes(csp_df)
check_script_unsafe_eval(csp_df)
check_script_unsafe_inline(csp_df)
check_src_http(csp_df)
check_wildcards(csp_df)
```
## crsspy Metrics
```{r cloc, echo=FALSE}

164
README.md

@ -1,2 +1,164 @@
# crsspy
[![Travis-CI Build
Status](https://travis-ci.org/hrbrmstr/crsspy.svg?branch=master)](https://travis-ci.org/hrbrmstr/crsspy)
[![Coverage
Status](https://codecov.io/gh/hrbrmstr/crsspy/branch/master/graph/badge.svg)](https://codecov.io/gh/hrbrmstr/crsspy)
[![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version/crsspy)](https://cran.r-project.org/package=crsspy)
# cspy
Content Security Policy Decomposer & Evaluator
## Description
Methods are provided to decompose, display, and validate content
security policy header values. Wraps the ‘Shape Security’ ‘salvation’
Java library (<https://github.com/shapesecurity/salvation>). Package
version tracks ‘salvation’ Java archive version.
## What’s Inside The Tin
The following functions are implemented:
Core:
- `fetch_csp`: Fetch and/or parse a content security policy header
value
- `has_csp`: Does a URL have a content security policy?
- `parse_csp`: Fetch and/or parse a content security policy header
value
- `validate_csp`: Validate a CSP
- `as.data.frame.csp`: Convert a parsed CSP into a data frame of
directives and values
Security/Safety Checks:
- `check_deprecated`: Tests for insecure CSP settings
- `check_ip_source`: Tests for insecure CSP settings
- `check_missing_directives`: Tests for insecure CSP settings
- `check_nonce_length`: Tests for insecure CSP settings
- `check_plain_url_schemes`: Tests for insecure CSP settings
- `check_script_unsafe_eval`: Tests for insecure CSP settings
- `check_script_unsafe_inline`: Tests for insecure CSP settings
- `check_src_http`: Tests for insecure CSP settings
- `check_wildcards`: Tests for insecure CSP settings
Testers:
- `allows_child_from_source`: Tests for what a parsed CSP allows
- `allows_connect_to`: Tests for what a parsed CSP allows
- `allows_font_from_source`: Tests for what a parsed CSP allows
- `allows_form_action`: Tests for what a parsed CSP allows
- `allows_frame_ancestor`: Tests for what a parsed CSP allows
- `allows_frame_from_source`: Tests for what a parsed CSP allows
- `allows_manifest_from_source`: Tests for what a parsed CSP allows
- `allows_media_from_source`: Tests for what a parsed CSP allows
- `allows_navigation`: Tests for what a parsed CSP allows
- `allows_object_from_source`: Tests for what a parsed CSP allows
- `allows_prefetch_from_source`: Tests for what a parsed CSP allows
- `allows_script_from_source`: Tests for what a parsed CSP allows
- `allows_script_with_nonce`: Tests for what a parsed CSP allows
- `allows_style_from_source`: Tests for what a parsed CSP allows
- `allows_style_with_nonce`: Tests for what a parsed CSP allows
- `allows_unsafe_inline_script`: Tests for what a parsed CSP allows
- `allows_unsafe_inline_style`: Tests for what a parsed CSP allows
- `allows_worker_from_source`: Tests for what a parsed CSP allows
## Installation
``` r
install.packages("cspy", repos = "https://cinc.rud.is/")
```
## Usage
``` r
library(cspy)
library(tibble) # for printing
# current version
packageVersion("cspy")
## [1] '2.6.0'
```
``` r
has_csp("https://community.rstudio.com")
## [1] TRUE
csp <- fetch_csp("https://community.rstudio.com")
csp
## base-uri
## object-src
## script-src 'unsafe-eval' 'report-sample' https://community.rstudio.com/logs/ https://community.rstudio.com/sidekiq/ https://community.rstudio.com/mini-profiler-resources/ https://community.rstudio.com/assets/ https://community.rstudio.com/brotli_asset/ https://community.rstudio.com/extra-locales/ https://community.rstudio.com/highlight-js/ https://community.rstudio.com/javascripts/ https://community.rstudio.com/plugins/ https://community.rstudio.com/theme-javascripts/ https://community.rstudio.com/svg-sprite/ https://www.google-analytics.com/analytics.js
## worker-src 'self' blob:
(csp_df <- as.data.frame(csp))
## # A tibble: 18 x 3
## directive value origin
## <chr> <chr> <chr>
## 1 base-uri 'none' https://community.rstudio.com
## 2 object-src 'none' https://community.rstudio.com
## 3 script-src 'unsafe-eval' https://community.rstudio.com
## 4 script-src 'report-sample' https://community.rstudio.com
## 5 script-src https://community.rstudio.com/logs/ https://community.rstudio.com
## 6 script-src https://community.rstudio.com/sidekiq/ https://community.rstudio.com
## 7 script-src https://community.rstudio.com/mini-profiler-resources/ https://community.rstudio.com
## 8 script-src https://community.rstudio.com/assets/ https://community.rstudio.com
## 9 script-src https://community.rstudio.com/brotli_asset/ https://community.rstudio.com
## 10 script-src https://community.rstudio.com/extra-locales/ https://community.rstudio.com
## 11 script-src https://community.rstudio.com/highlight-js/ https://community.rstudio.com
## 12 script-src https://community.rstudio.com/javascripts/ https://community.rstudio.com
## 13 script-src https://community.rstudio.com/plugins/ https://community.rstudio.com
## 14 script-src https://community.rstudio.com/theme-javascripts/ https://community.rstudio.com
## 15 script-src https://community.rstudio.com/svg-sprite/ https://community.rstudio.com
## 16 script-src https://www.google-analytics.com/analytics.js https://community.rstudio.com
## 17 worker-src 'self' https://community.rstudio.com
## 18 worker-src blob: https://community.rstudio.com
allows_unsafe_inline_script(csp)
## [1] FALSE
check_deprecated(csp_df)
check_ip_source(csp_df)
check_missing_directives(csp_df)
check_nonce_length(csp_df)
check_plain_url_schemes(csp_df)
check_script_unsafe_eval(csp_df)
## Category: script-unsafe-eval
## Severity: HIGH
## Message: 'unsafe-eval' allows the execution of code injected into DOM APIs such as eval().
##
## # A tibble: 1 x 3
## directive value origin
## * <chr> <chr> <chr>
## 1 script-src 'unsafe-eval' https://community.rstudio.com
check_script_unsafe_inline(csp_df)
check_src_http(csp_df)
check_wildcards(csp_df)
```
## crsspy Metrics
| Lang | \# Files | (%) | LoC | (%) | Blank lines | (%) | \# Lines | (%) |
| :---- | -------: | ---: | --: | ---: | ----------: | ---: | -------: | ---: |
| R | 11 | 0.65 | 509 | 0.73 | 134 | 0.71 | 221 | 0.73 |
| Maven | 1 | 0.06 | 70 | 0.10 | 6 | 0.03 | 5 | 0.02 |
| XML | 1 | 0.06 | 65 | 0.09 | 0 | 0.00 | 0 | 0.00 |
| Java | 2 | 0.12 | 26 | 0.04 | 8 | 0.04 | 6 | 0.02 |
| Rmd | 1 | 0.06 | 21 | 0.03 | 37 | 0.20 | 69 | 0.23 |
| make | 1 | 0.06 | 11 | 0.02 | 4 | 0.02 | 0 | 0.00 |
## Code of Conduct
Please note that this project is released with a [Contributor Code of
Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree
to abide by its terms.

3
man/csp_security_checkers.Rd

@ -2,7 +2,6 @@
% Please edit documentation in R/findings.R
\name{csp_security_checkers}
\alias{csp_security_checkers}
\alias{ensure_csp_df}
\alias{check_script_unsafe_inline}
\alias{check_script_unsafe_eval}
\alias{check_plain_url_schemes}
@ -14,8 +13,6 @@
\alias{check_src_http}
\title{Tests for insecure CSP settings}
\usage{
ensure_csp_df(csp_df)
check_script_unsafe_inline(csp_df)
check_script_unsafe_eval(csp_df)

3
man/has_csp.Rd

@ -15,3 +15,6 @@ depending on the method used)}
\description{
Does a URL have a content security policy?
}
\examples{
has_csp("https://rud.is/")
}

4
man/parse_csp.Rd

@ -22,6 +22,10 @@ depending on the method used)}
Use \code{\link[=fetch_csp]{fetch_csp()}} to load & parse a CSP from a remote site. Use \code{\link[=parse_csp]{parse_csp()}}
to parse an already fetched or composed CSP.
}
\examples{
parse_csp("default-src: 'none'", "https://example.com")
fetch_csp("https://rud.is/")
}
\references{
\href{https://www.w3.org/TR/CSP3/}{Content Security Policy Level 3}
}

2
tests/test-all.R

@ -1,2 +1,2 @@
library(testthat)
test_check("crsspy")
test_check("cspy")

28
tests/testthat/test-cspy.R

@ -1,6 +1,26 @@
context("minimal package functionality")
test_that("we can do something", {
context("Presence test works")
#expect_that(some_function(), is_a("data.frame"))
expect_true(has_csp("https://rud.is/"))
})
context("Parser works")
x1 <- fetch_csp("https://rud.is/")
expect_is(x1, "csp")
x2 <- parse_csp("default-src 'none'", "https://example.com")
expect_is(x2, "csp")
context("Data framer works")
expect_is(as.data.frame(x1), "data.frame")
context("Validation works")
expect_true(nrow(validate_csp(x1)) == 0)
expect_true(nrow(validate_csp(x2)) == 0)
context("Testers work")
expect_is(allows_unsafe_inline_script(x1), "logical")
expect_is(allows_unsafe_inline_script(x2), "logical")
check_script_unsafe_inline(x2)

Loading…
Cancel
Save