Skip to content

Commit

Permalink
Merge pull request #5169 from nanasess/automated-penetration-testing-…
Browse files Browse the repository at this point in the history
…vulnerability

OWASP ZAP のアクティブスキャンを自動化する試み
  • Loading branch information
Kiyotaka Oku authored Sep 21, 2021
2 parents 2a96a78 + 4fd6a75 commit d59bc17
Show file tree
Hide file tree
Showing 16 changed files with 4,493 additions and 0 deletions.
52 changes: 52 additions & 0 deletions .github/workflows/penetration-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Penetration testing for EC-CUBE
on:
schedule:
- cron: '0 15 * * 1'

jobs:
PenetrationTest:
name: Penetration testing
runs-on: ${{ matrix.operating-system }}
strategy:
fail-fast: false
matrix:
operating-system: [ ubuntu-18.04 ]
group:
- 'test/front_login/contact.test.ts'
- 'test/front_guest/contact.test.ts'
- 'test/admin/order_mail.test.ts'

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Setup to EC-CUBE
run: |
sudo chown -R 1001:1000 zap
sudo chmod -R g+w zap
docker-compose -f docker-compose.yml -f docker-compose.pgsql.yml -f docker-compose.dev.yml -f docker-compose.owaspzap.yml -f docker-compose.owaspzap.daemon.yml up -d
docker-compose -f docker-compose.yml -f docker-compose.pgsql.yml -f docker-compose.dev.yml -f docker-compose.owaspzap.yml -f docker-compose.owaspzap.daemon.yml exec -T ec-cube bin/console doctrine:schema:create --env=dev
docker-compose -f docker-compose.yml -f docker-compose.pgsql.yml -f docker-compose.dev.yml -f docker-compose.owaspzap.yml -f docker-compose.owaspzap.daemon.yml exec -T ec-cube bin/console eccube:fixtures:load --env=dev
docker-compose -f docker-compose.yml -f docker-compose.pgsql.yml -f docker-compose.dev.yml -f docker-compose.owaspzap.yml -f docker-compose.owaspzap.daemon.yml exec -T ec-cube bin/console eccube:fixtures:generate --products=5 --customers=1 --orders=5
docker-compose -f docker-compose.yml -f docker-compose.pgsql.yml -f docker-compose.dev.yml -f docker-compose.owaspzap.yml -f docker-compose.owaspzap.daemon.yml exec -T ec-cube bin/console doctrine:query:sql "UPDATE dtb_customer SET email = 'zap_user@example.com' WHERE id = 1;"
sed -i 's!APP_ENV: "dev"!APP_ENV: "prod"!g' docker-compose.yml
docker-compose -f docker-compose.yml -f docker-compose.pgsql.yml -f docker-compose.dev.yml -f docker-compose.owaspzap.yml -f docker-compose.owaspzap.daemon.yml up -d ec-cube
- name: yarn install
working-directory: zap/selenium/ci/TypeScript
run: yarn install
- name: Penetration testing
working-directory: zap/selenium/ci/TypeScript
env:
GROUP: ${{ matrix.group }}
run: yarn jest ${GROUP}
- env:
GROUP: ${{ matrix.group }}
if: always()
run: echo "ARTIFACT_NAME=$(echo ${GROUP} | sed 's,/,-,g')" >> $GITHUB_ENV
- name: Upload evidence
if: always()
uses: actions/upload-artifact@v2
with:
name: zap-${{ env.ARTIFACT_NAME }}-session
path: zap/sessions
5 changes: 5 additions & 0 deletions docker-compose.owaspzap.daemon.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
version: "3"

services:
zap:
command: bash -c "zap.sh -daemon -addonupdate -addoninstall help_ja_JP -addoninstall wappalyzer -addoninstall sequence -addonuninstall hud -configfile /zap/wrk/options.properties -certpubdump /zap/wrk/owasp_zap_root_ca.cer -host 0.0.0.0 -port 8090 -config api.addrs.addr.name=.* -config api.addrs.addr.regex=true"
1 change: 1 addition & 0 deletions zap/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/owasp_zap_root_ca.cer
/sessions
!/sessions/.gitkeep
97 changes: 97 additions & 0 deletions zap/options.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,103 @@ anticsrf.tokens.token\(4\).name=form[_token]
anticsrf.tokens.token\(4\).enabled=true
anticsrf.tokens.token\(5\).name=shopping_shipping[_token]
anticsrf.tokens.token\(5\).enabled=true
anticsrf.tokens.token\(6\).name=contact[_token]
anticsrf.tokens.token\(6\).enabled=true
anticsrf.tokens.token\(7\).name=coupon_use[_token]
anticsrf.tokens.token\(7\).enabled=true
anticsrf.tokens.token\(8\).name=customer_address[_token]
anticsrf.tokens.token\(8\).enabled=true
anticsrf.tokens.token\(9\).name=entry[_token]
anticsrf.tokens.token\(9\).enabled=true
anticsrf.tokens.token\(10\).name=admin_product[_token]
anticsrf.tokens.token\(10\).enabled=true
anticsrf.tokens.token\(11\).name=admin_search_product[_token]
anticsrf.tokens.token\(11\).enabled=true
anticsrf.tokens.token\(12\).name=admin_class_name[_token]
anticsrf.tokens.token\(12\).enabled=true
anticsrf.tokens.token\(13\).name=admin_class_category[_token]
anticsrf.tokens.token\(13\).enabled=true
anticsrf.tokens.token\(14\).name=class_name[_token]
anticsrf.tokens.token\(14\).enabled=true
anticsrf.tokens.token\(15\).name=admin_category[_token]
anticsrf.tokens.token\(15\).enabled=true
anticsrf.tokens.token\(16\).name=admin_product_tag[_token]
anticsrf.tokens.token\(16\).enabled=true
anticsrf.tokens.token\(17\).name=product_review[_token]
anticsrf.tokens.token\(17\).enabled=true
anticsrf.tokens.token\(18\).name=product_review_search[_token]
anticsrf.tokens.token\(18\).enabled=true
anticsrf.tokens.token\(19\).name=admin_search_order[_token]
anticsrf.tokens.token\(19\).enabled=true
anticsrf.tokens.token\(20\).name=order_pdf[_token]
anticsrf.tokens.token\(20\).enabled=true
anticsrf.tokens.token\(21\).name=order[_token]
anticsrf.tokens.token\(21\).enabled=true
anticsrf.tokens.token\(22\).name=admin_order_mail[_token]
anticsrf.tokens.token\(22\).enabled=true
anticsrf.tokens.token\(23\).name=coupon[_token]
anticsrf.tokens.token\(23\).enabled=true
anticsrf.tokens.token\(24\).name=admin_search_customer[_token]
anticsrf.tokens.token\(24\).enabled=true
anticsrf.tokens.token\(25\).name=admin_news[_token]
anticsrf.tokens.token\(25\).enabled=true
anticsrf.tokens.token\(26\).name=admin_layout[_token]
anticsrf.tokens.token\(26\).enabled=true
anticsrf.tokens.token\(27\).name=main_edit[_token]
anticsrf.tokens.token\(27\).enabled=true
anticsrf.tokens.token\(28\).name=block[_token]
anticsrf.tokens.token\(28\).enabled=true
anticsrf.tokens.token\(29\).name=recommend_product[_token]
anticsrf.tokens.token\(29\).enabled=true
anticsrf.tokens.token\(30\).name=shop_master[_token]
anticsrf.tokens.token\(30\).enabled=true
anticsrf.tokens.token\(31\).name=payment_register[_token]
anticsrf.tokens.token\(31\).enabled=true
anticsrf.tokens.token\(32\).name=delivery[_token]
anticsrf.tokens.token\(32\).enabled=true
anticsrf.tokens.token\(33\).name=tax_rule[_token]
anticsrf.tokens.token\(33\).enabled=true
anticsrf.tokens.token\(34\).name=mail[_token]
anticsrf.tokens.token\(34\).enabled=true
anticsrf.tokens.token\(35\).name=admin_member[_token]
anticsrf.tokens.token\(35\).enabled=true
anticsrf.tokens.token\(36\).name=admin_security[_token]
anticsrf.tokens.token\(36\).enabled=true
anticsrf.tokens.token\(37\).name=admin_search_login_history[_token]
anticsrf.tokens.token\(37\).enabled=true
anticsrf.tokens.token\(38\).name=admin_system_log[_token]
anticsrf.tokens.token\(38\).enabled=true
anticsrf.tokens.token\(39\).name=admin_system_masterdata[_token]
anticsrf.tokens.token\(39\).enabled=true
anticsrf.tokens.token\(40\).name=admin_system_masterdata_edit[_token]
anticsrf.tokens.token\(40\).enabled=true
anticsrf.tokens.token\(41\).name=api_admin_client[_token]
anticsrf.tokens.token\(41\).enabled=true
anticsrf.tokens.token\(42\).name=web_hook[_token]
anticsrf.tokens.token\(42\).enabled=true
anticsrf.tokens.token\(43\).name=search_plugin[_token]
anticsrf.tokens.token\(43\).enabled=true
anticsrf.tokens.token\(44\).name=product_review_config[_token]
anticsrf.tokens.token\(44\).enabled=true
anticsrf.tokens.token\(45\).name=securitychecker4_config[_token]
anticsrf.tokens.token\(45\).enabled=true
anticsrf.tokens.token\(46\).name=admin_template[_token]
anticsrf.tokens.token\(46\).enabled=true
anticsrf.tokens.token\(47\).name=admin_authentication[_token]
anticsrf.tokens.token\(47\).enabled=true
anticsrf.tokens.token\(48\).name=mail_magazine[_token]
anticsrf.tokens.token\(48\).enabled=true
anticsrf.tokens.token\(49\).name=mail_magazine_template_edit[_token]
anticsrf.tokens.token\(49\).enabled=true
anticsrf.tokens.token\(50\).name=sales_report[_token]
anticsrf.tokens.token\(50\).enabled=true
anticsrf.tokens.token\(51\).name=admin_csv_import[_token]
anticsrf.tokens.token\(51\).enabled=true
anticsrf.tokens.token\(52\).name=plugin_local_install[_token]
anticsrf.tokens.token\(52\).enabled=true
anticsrf.tokens.token\(53\).name=admin_change_password[_token]
anticsrf.tokens.token\(53\).enabled=true
scanner.antiCSFR=true
httpsessions.tokens.token\(0\).name=eccube
httpsessions.tokens.token\(0\).enabled=true
httpsessions.tokens.token\(1\).name=ecsessid
Expand Down
8 changes: 8 additions & 0 deletions zap/selenium/ci/TypeScript/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
; Unix-style newlines
[*]
charset = utf-8
end_of_line = LF
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
6 changes: 6 additions & 0 deletions zap/selenium/ci/TypeScript/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/preset-typescript'
],
};
20 changes: 20 additions & 0 deletions zap/selenium/ci/TypeScript/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "TypeScript",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.15.5",
"@babel/preset-env": "^7.15.4",
"@babel/preset-typescript": "^7.15.0",
"@types/jest": "^27.0.1",
"@types/request-promise-native": "^1.0.18",
"@types/selenium-webdriver": "^4.0.15",
"babel-jest": "^27.1.0",
"jest": "^27.1.0",
"selenium-webdriver": "^4.0.0-rc-1",
"ts-jest": "^27.0.5",
"typescript": "^4.4.2",
"zaproxy": "^1.0.1"
}
}
80 changes: 80 additions & 0 deletions zap/selenium/ci/TypeScript/test/admin/order_mail.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Builder, By, until } from 'selenium-webdriver'
import { ZapClient, Mode, ContextType, Risk } from '../../utils/ZapClient';
import { intervalRepeater } from '../../utils/Progress';
import { SeleniumCapabilities } from '../../utils/SeleniumCapabilities';
const zapClient = new ZapClient('http://127.0.0.1:8090');

jest.setTimeout(6000000);

const baseURL = 'https://ec-cube/admin';
const url = baseURL + '/order/4/mail';

beforeAll(async () => {
await zapClient.setMode(Mode.Protect);
await zapClient.newSession('/zap/wrk/sessions/admin_order_mail', true);
await zapClient.importContext(ContextType.Admin);

if (!await zapClient.isForcedUserModeEnabled()) {
await zapClient.setForcedUserModeEnabled();
expect(await zapClient.isForcedUserModeEnabled()).toBeTruthy();
}
});

test('受注管理>メール通知 - GET', async () => {
const driver = await new Builder()
.withCapabilities(SeleniumCapabilities)
.build();

try {
await driver.get(url);
const title = await driver.wait(
until.elementLocated(By.className('c-pageTitle__title'))
, 10000).getText();
expect(title).toBe('メール通知');

const scanId = await zapClient.activeScanAsUser(url, 2, 55, false, null, 'GET');

await intervalRepeater(async () => await zapClient.getActiveScanStatus(scanId), 5000);

await zapClient.getAlerts(url, 0, 1, Risk.High)
.then(alerts => alerts.forEach((alert: any) => {
throw new Error(alert.name);
}));
} finally {
driver && await driver.quit()
}
});

test('受注管理>メール通知(確認ページ) - POST', async () => {
const driver = await new Builder()
.withCapabilities(SeleniumCapabilities)
.build();

try {
await driver.get(url);
const title = await driver.wait(
until.elementLocated(By.className('c-pageTitle__title'))
, 10000).getText();
expect(title).toBe('メール通知');

await driver.findElement(By.xpath('//*[@id="template-change"]/option[2]')).click();
const subject = await driver.wait(
until.elementLocated(By.xpath('//*[@id="admin_order_mail_mail_subject"]'))
, 10000).getAttribute('value');
expect(subject).toBe('ご注文ありがとうございます');

await driver.findElement(By.xpath('//*[@id="order-mail-form"]/div[2]/div/div/div[2]/div/div/button')).click();

const message = await zapClient.getLastMessage(url);
const scanId = await zapClient.activeScanAsUser(url, 2, 55, false, null, 'POST', message.requestBody);

await intervalRepeater(async () => await zapClient.getActiveScanStatus(scanId), 5000);

await zapClient.getAlerts(url, 0, 1, Risk.High)
.then(alerts => alerts.forEach((alert: any) => {
throw new Error(alert.name);
}));
} finally {
driver && await driver.quit()
}
});
Loading

0 comments on commit d59bc17

Please sign in to comment.