Introduction
As a security professional, you’re proud of your static code scanning program. You run scans every month. Fortify Static Code Analyzer cranks out consistent results. Software Security Center lets developers exhaustively research each and every Common Weakness Enumeration (CWE). Surely, they have enough information to effectively manage their security backlog?
That was you think, until an enlightened developer asks a very simple question.
“What’s the difference between the previous scan and this one? Did I open any new weaknesses?”
It’s a very good question, isn’t it? Very logical. It’s something I’d like to know as a security practitioner, too! Unfortunately, it’s hard to get that information across your portfolio in an automated way. And if you have a hundred applications you’re responsible for scanning, manually gathering that information just isn’t an option.
Fortunately, as we’ve talked about in previous posts, Software Security Center is built on a logical, well-designed database. The data’s there. And this post will show you how to extract that kind of comparison.
Comparing Two Fortify Static Code Analyzer Scans
The first thing we’ll need to do is pull scan information out of the table that holds master scan information. That table is helpfully naned:
scan
You can pull the information with this query:
SELECT dbo.BigInt2Date(startDate) AS rundate, * FROM dbo.scan WHERE scaBuildId LIKE 'nsm%' ORDER BY id DESC; -- pull out id
If you haven’t read the previous posts, you might not know what dbo.BigInt2Date does. A previous post in this series describes it.
Notice the LIKE portion of the query? What you put here depends on your application naming conventions. My application is named “nsm”, so I want to see all scans dealing with it. The build ID I’m using includes the version number. For example:
sourceanalyzer -b nsm_1.0.0 ...
Since I’ve only run two scans on that application, my query’s results look like this:
The key information here is the “id” column. The most recent scan is ID 13; the next most recent is 12. Remember those numbers!
Fortify’s Software Security Center (SSC) stores the issues that a scan identifies in a table that’s logically named scan_issue. That’s the table we’ll query to compare scans 13 and 12. The way I use SSC, if I mark something “Not an Issue,” I don’t want it to show up on reports. So we’ll exclude those items.
Please consider this query:
SELECT * FROM scan_issue a WHERE a.scan_id = 13 -- Newer id of scan AND a.issueInstanceId NOT IN (SELECT b.issueInstanceId FROM scan_issue b WHERE b.scan_id = 12 AND b.issueInstanceId = a.issueInstanceId) -- older id of scan AND a.issue_id NOT IN (SELECT c.issue_id FROM audithistory c WHERE c.issue_id = a.issue_id AND Upper(c.newValue) = Upper('Not an issue') AND c.seqNumber = (SELECT MAX(seqNumber) FROM audithistory WHERE issue_id = a.issue_id AND Upper(c.newValue) = Upper('Not an issue'))) ORDER BY friority;
For my particular two scans, the results look like this:
This will list all of the issues that you’ve introduced between the first and second query. In other words, after the scan whose ID was 12, the developer did some work (maybe adding another JSP) and resulted, in scan 13, with some more weaknesses.
You could export this data to give to the developers as a handy reference. They could also copy the issueInstanceId column value and look it up in SSC. For example, in my scans, searching for issueInstanceId in SSC 1D1BBAB0003E559A14D4CD450C9A579E shows this screen:
What’s cool is that I don’t have to even navigate into the Applications to search for the Issue Instance ID. I can just search from the Dashboard. And if I click into the screen above, I get the weakness’ details:
So, with very little effort, you can tell the developers you support exactly which weaknesses they introduced between two scans.
With a minor tweak, you could turn it into counts that you can use for trending:
SELECT COUNT(a.issueInstanceId) AS thecount, a.friority FROM scan_issue a WHERE a.scan_id = 13 -- Newer id of scan AND a.issueInstanceId NOT IN (SELECT b.issueInstanceId FROM scan_issue b WHERE b.scan_id = 12 AND b.issueInstanceId = a.issueInstanceId) -- older id of scan AND a.issue_id NOT IN (SELECT c.issue_id FROM audithistory c WHERE c.issue_id = a.issue_id AND Upper(c.newValue) = Upper('Not an issue') AND c.seqNumber = (SELECT MAX(seqNumber) FROM audithistory WHERE issue_id = a.issue_id AND Upper(c.newValue) = Upper('Not an issue'))) GROUP BY friority ORDER BY friority;
This query will show you a count by Critical, High, Medium, and Low.
A Caveat
There are a few things you should keep in mind. For example, Fortify Static Code Analyzer seems to consider a weakness unique based on:
- The file name
- The line number
- The weakness itself
Let’s say you take the same path I do and mark some items as “Not an Issue.” Those Items will resurface if the source codes significantly.
For example, page1.jsp’s line 10 might have an XSS weakness. Let’s say that before the first scan (ID 12 in our examples) the developer marked the item “Not an Issue” because the code contained mitigating controls (input sanitization, for example). If they did that, the report based on the scan whose ID is 12 would not show the weakness.
But let’s say the developer adds 30 lines of code above line 10 in page1.jsp. That means page1.jsp now has an XSS weakness on line 40. The developer had previously marked it “Not an Issue,” so they expect it not to show up on the scan.
Unfortunately, Fortify will likely consider this a new weakness, and it will show up in the queries in this post.
That’s not really a query issue. It’s something that’s just a part of Fortify. I’ve not been able to come up with a better approach. In other words, it seems like this is just part of using Fortify.
Summary
Fortify’s Software Security Center has a lot to offer in terms of working with weaknesses. For a developer’s day to day activity, it’s likely SSC is going to give you what you need. But if you need to provide either detailed data about the difference between two scans, or if you just need to provide counts, this post should give you the queries you need.
Have you tried these queries? Do you have another approach you prefer? Please feel free to talk about it in the comments!