Skip to content

Commit

Permalink
feat: Rule for hard-coded key
Browse files Browse the repository at this point in the history
  • Loading branch information
kgilpin committed Aug 2, 2022
1 parent 00c1d5f commit 61a3b52
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 0 deletions.
7 changes: 7 additions & 0 deletions packages/scanner/doc/labels/crypto.decrypt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: crypto.decrypt
rules:
- hard-coded-key
---

A function that performs decryption.
1 change: 1 addition & 0 deletions packages/scanner/doc/labels/crypto.encrypt.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: crypto.encrypt
rules:
- hard-coded-key
- unauthenticated-encryption
---

Expand Down
7 changes: 7 additions & 0 deletions packages/scanner/doc/labels/crypto.set_key.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: crypto.set_key
rules:
- hard-coded-key
---

A function that sets the crytographic key for encryption, decryption, or signature.
12 changes: 12 additions & 0 deletions packages/scanner/doc/labels/string.unpack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
name: string.unpack
rules:
- hard-coded-key
---

Unpacks a string into binary from a printable encoding such as hex or Base64.

## Examples

- Ruby [String#unpack](https://ruby-doc.org/core-3.1.2/String.html#method-i-unpack)
- Ruby [String#unpack1](https://ruby-doc.org/core-3.1.2/String.html#method-i-unpack1)
14 changes: 14 additions & 0 deletions packages/scanner/doc/rules/hard-coded-key.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
rule: hard-coded-key
name: Hard coded key
title: Hard-coded key
references:
A02:2021: https://owasp.org/Top10/A02_2021-Cryptographic_Failures/
impactDomain: Security
labels:
- crypto.encrypt
- crypto.decrypt
- crypto.set_key
- string.unpack
scope: root
---
12 changes: 12 additions & 0 deletions packages/scanner/src/rules/hard-coded-key/metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Metadata } from '../lib/metadata';

export default {
title: 'Hard-coded key',
scope: 'root',
enumerateScope: true,
impactDomain: 'Security',
references: {
'A02:2021': 'https://owasp.org/Top10/A02_2021-Cryptographic_Failures/',
},
labels: ['crypto.encrypt', 'crypto.decrypt', 'crypto.set_key', 'string.unpack'],
} as Metadata;
44 changes: 44 additions & 0 deletions packages/scanner/src/rules/hard-coded-key/rule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Event } from '@appland/models';
import { AppMapIndex, MatcherResult, RuleLogic } from '../../types';

function matcher(event: Event, appMapIndex: AppMapIndex): MatcherResult {
if (!event.receiver) return;

const receiverObjectId = event.receiver.object_id;
const setKey = appMapIndex.appMap.events.find(
(evt) =>
evt.isCall() &&
evt.receiver?.object_id === receiverObjectId &&
evt.labels.has('crypto.set_key')
);
if (!setKey) return;

const keyObject = setKey.parameters![0];
if (!keyObject) return;

const keyObjectId = keyObject.object_id;
const obtainKey = appMapIndex.appMap.events.find(
(evt) =>
evt.isReturn() &&
evt !== setKey.returnEvent &&
!evt.codeObject.labels.has('string.unpack') &&
evt.returnValue?.object_id === keyObjectId
);
if (!obtainKey) {
return [
{
level: 'warning',
event,
message: `Cryptographic key is not obtained from a function, and may be hard-coded`,
participatingEvents: { 'crypto.set_key': setKey },
},
];
}
}

export default function rule(): RuleLogic {
return {
matcher,
where: (e: Event) => e.labels.has('crypto.encrypt'),
};
}
1 change: 1 addition & 0 deletions packages/scanner/src/sampleConfig/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ checks:
# - rule: circular-dependency
- rule: deserialization-of-untrusted-data
- rule: exec-of-untrusted-command
- rule: hard-coded-key
- rule: http-500
# - rule: illegal-package-dependency
# - rule: incompatible-http-client-request
Expand Down
29 changes: 29 additions & 0 deletions packages/scanner/test/scanner/hardCodedKey.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Check from '../../src/check';
import { loadRule } from '../../src/configuration/configurationProvider';
import { scan } from '../util';

describe('hard-coded key', () => {
it('found', async () => {
const rule = await loadRule('hard-coded-key');
const { findings } = await scan(
new Check(rule),
'./ruby/fixture/tmp/appmap/minitest/Crypt_hard_coded_key.appmap.json'
);
expect(findings).toHaveLength(1);
const finding1 = findings[0];
expect(finding1.ruleId).toEqual('hard-coded-key');
expect(finding1.event.id).toEqual(4);
expect(finding1.message).toEqual(
`Cryptographic key is not obtained from a function, and may be hard-coded`
);
expect(finding1.relatedEvents).toHaveLength(2);
});
it('not found', async () => {
const rule = await loadRule('hard-coded-key');
const { findings } = await scan(
new Check(rule),
'./ruby/fixture/tmp/appmap/minitest/Crypt_random_key.appmap.json'
);
expect(findings).toHaveLength(0);
});
});

0 comments on commit 61a3b52

Please sign in to comment.