Content Security Policy

I’ve recently been developing a WordPress replacement for https://found-art.roguelj.co.uk. WordPress is overkill for the needs of that site, and the additional functionality that I required would have had to have been provided by 3rd party plug-ins. Or I could have created the plug-ins myself, but it’s been a while since I coded any PHP.

In addition to this, I have also been wanting to test out some web app vulnerability scanners. Development of the new site for Found Art presented a perfect opportunity to test out ZAP – Zed Attack Proxy.

https://www.zaproxy.org

 

 

Now, I’ve never used ZAP before, so I just dived in and ran it using ‘Attack’ mode against the locally-running dev-site. It flagged several issues, all related to missing Content Security Policy headers.

Zed Attack Proxy Results
Zed Attack Proxy Results

A quick internet search on how to fix this for an ASP Core NET website lead me to the following page https://the-runtime.dev/articles/content-security-policy-headers. Implementing the policies was easy,  with the pertinent code being as follows:

app.Use(async (context, next) =>
{
    var nonce = Convert.ToBase64String(RandomNumberGenerator.GetBytes(16));
    context.Items["CspNonce"] = nonce;

    context.Response.Headers.Append(
        "Content-Security-Policy",
        $"default-src 'self'; script-src 'self' 'nonce-{nonce}'");

    await next();
});

The code above was specifically related to using a nonce for inline scripts. All well and good, and things worked as required once I had set the nonce in the appropriate scripts, as follows:

@{
    ViewData["Title"] = "Home Page";
    var nonce = Context.Items["CspNonce"]?.ToString();
}


I did have to tweak the code a little, because by default it didn’t include the other policies created by the CspBuilder (details on the page, go check it out)

context.Response.Headers.Append(
    Constants.Headers.CONTENT_SECURITY_POLICY_HEADER,
    $"{csp}; script-src 'nonce-{nonce}' 'self'; style-src 'nonce-{nonce}' 'self';");

A line in the middleware for the request (app.Use) caught my eye:

Convert.ToBase64String(RandomNumberGenerator.GetBytes(16)

This middleware runs for every request and therefore it should be as fast as possible. I wondered if there was a faster way to get 16 random characters, and it appears that there is:

var nonce = Random.Shared.GetString("abcdef0123456789", 16);

The documentation for GetString can be found here.

This will basically return a hex string, however we’re limiting the characters that the function can use so the available entropy is not as high as it could be. Increasing the pool of characters to draw from does come with a little quirk, stick around for part 2 for the details.

 

The Return

Ok, after a couple of years experimenting with a different website (that I also left to rot), I’ve decided to return to the blog format with most of the old content still intact. I’ve tidied up some posts that were no longer relevant and updated where necessary.

The graffiti art photo posts have moved to their own subdomain, which can be found here:

https://found-art.roguelj.co.uk

The music content posts will also be moved to their own sub-domain in due course.

Open Sales Order Lines SQL query

Open Order Rows SQL Execution Plan

SQL Query for SAP Business One to return a list of open sales order lines at row detail.

SELECT
     T0.[DocNum],
     T0.[DocDate],
     T0.[NumAtCard],
     T0.[CardCode],
     T0.[CardName],
     T1.[ItemCode],
     T1.[WhsCode],
     T1.[Quantity],
     T1.[OpenQty],
     T1.[ShipDate],
     T2.[SlpName]
 FROM    
     [dbo].[ORDR] T0
     INNER JOIN [dbo].[RDR1] T1 ON T0.[DocEntry] = T1.[DocEntry]
     LEFT  JOIN [dbo].[OSLP] T2 ON T1.[SlpCode] = T2.[SlpCode]

 WHERE
     T1.[LineStatus] !='C'

The handy thing about the Orders, Delivery, and Invoices tables (and many other tables besides), is that the schema’s are the same. So you can re-purpose the query by swapping out the table names – for instance, the following will give you Open Sales Deliveries:

 SELECT
     T0.[DocNum],
     T0.[DocDate],
     T0.[NumAtCard],
     T0.[CardCode],
     T0.[CardName],
     T1.[ItemCode],
     T1.[WhsCode],
     T1.[Quantity],
     T1.[OpenQty],
     T1.[ShipDate],
     T2.[SlpName]
 FROM    
     [dbo].[ODLN] T0
     INNER JOIN [dbo].[DLN1] T1 ON T0.[DocEntry] = T1.[DocEntry]
     LEFT  JOIN [dbo].[OSLP] T2 ON T1.[SlpCode] = T2.[SlpCode]

 WHERE
     T1.[LineStatus] !='C' 

Columns returned:

  • Document Number (DocNum)
  • Document Date (DocDate)
  • Customer Reference (NumAtCard)
  • Customer Code (CardCode)
  • Customer Name (CardName)
  • Item (ItemCode)
  • Warehouse (WhsCode)
  • Quantity
  • Open Quantity (OpenQty)
  • Delivery Date (ShipDate)
  • Sales Person (SlpName)

You can find this query, and more over at my GitHub page: https://github.com/roguelj/SAP-Business-One-SQL-Queries

There are more SAP Business One queries on my blog, and you can find them here directly. For those of you that are integrating with SAP Business One more deeply, you can find related articles about the DI API here.