-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generate apps with SecTester #743
Changes from 18 commits
5fa84d9
7da39fa
41e65ee
ac63606
e3f2f75
f5f6f78
258c373
20ab2a9
e347017
0fc43d2
c11c9e4
451a5e6
563467e
b9f79de
92222d4
ed8b509
8808a3d
f28f949
1784c7d
31e058f
c4f33a1
06e5ad4
0f123dd
5d39f40
7d306c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
require "../spec_helper" | ||
|
||
include ShouldRunSuccessfully | ||
include WithProjectCleanup | ||
|
||
describe "Initializing a new web project" do | ||
it "creates a full web app successfully" do | ||
|
@@ -16,7 +17,8 @@ describe "Initializing a new web project" do | |
|
||
File.delete("test-project/.env") | ||
compile_and_run_specs_on_test_project | ||
File.read(".github/workflows/ci.yml").should contain "postgres" | ||
File.read("test-project/Procfile").should contain "bin/app" | ||
File.read("test-project/.github/workflows/ci.yml").should contain "postgres" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. turns out this has been wrong for a while 😅 |
||
File.read("test-project/public/mix-manifest.json").should contain "images/cat.gif" | ||
File.exists?("test-project/public/favicon.ico").should eq true | ||
File.exists?("test-project/.env").should eq true | ||
|
@@ -139,20 +141,3 @@ private def compile_and_run_specs_on_test_project | |
should_run_successfully "crystal spec" | ||
end | ||
end | ||
|
||
private def with_project_cleanup(project_directory = "test-project", skip_db_drop = false) | ||
yield | ||
|
||
FileUtils.cd(project_directory) { | ||
output = IO::Memory.new | ||
Process.run( | ||
"lucky db.drop", | ||
output: output, | ||
shell: true | ||
) | ||
|
||
output.to_s.should contain("Done dropping") | ||
} unless skip_db_drop | ||
ensure | ||
FileUtils.rm_rf project_directory | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
require "../spec_helper" | ||
|
||
{% if env("RUN_SEC_TESTER_SPECS") == "1" %} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Anyone that wants to run this spec locally would need a Bright API key... That's not really going to happen, so we can treat this like the Heroku specs. As long as this spec passes in CI, and the rest pass locally, we should be fine |
||
include ShouldRunSuccessfully | ||
include WithProjectCleanup | ||
|
||
describe "Apps with SecTester enabled" do | ||
it "creates a full app with sec_tester enabled" do | ||
puts "Web app with SecTester: Running integration spec. This might take awhile...".colorize(:yellow) | ||
with_project_cleanup do | ||
should_run_successfully "crystal run src/lucky.cr -- init.custom test-project --with-sec-test" | ||
|
||
FileUtils.cd "test-project" do | ||
File.read("spec/setup/sec_tester.cr").should contain "LuckySecTester" | ||
File.read(".github/workflows/ci.yml").should contain "-Dwith_sec_tests" | ||
File.read("spec/flows/security_spec.cr").should contain "dom_xss" | ||
should_run_successfully "./script/setup" | ||
should_run_successfully "crystal spec -Dwith_sec_tests" | ||
end | ||
end | ||
end | ||
end | ||
{% end %} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
module WithProjectCleanup | ||
private def with_project_cleanup(project_directory = "test-project", skip_db_drop = false) : Nil | ||
yield | ||
|
||
FileUtils.cd(project_directory) { | ||
output = IO::Memory.new | ||
Process.run( | ||
"lucky db.drop", | ||
output: output, | ||
shell: true | ||
) | ||
|
||
output.to_s.should contain("Done dropping") | ||
} unless skip_db_drop | ||
ensure | ||
FileUtils.rm_rf project_directory | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
{% skip_file unless flag?(:with_sec_tests) %} | ||
# Run these specs with `crystal spec -Dwith_sec_tests` | ||
|
||
require "../spec_helper" | ||
|
||
describe "SecTester" do | ||
<%- if browser? -%> | ||
<%- if generate_auth? -%> | ||
it "tests the sign_in for dom based XSS" do | ||
scan_with_cleanup do |scanner| | ||
target = scanner.build_target(SignIns::New) | ||
scanner.run_check( | ||
scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", | ||
tests: "dom_xss", | ||
target: target | ||
) | ||
end | ||
end | ||
|
||
it "tests the sign_in page for SQLi, OSI, XSS attacks" do | ||
scan_with_cleanup do |scanner| | ||
target = scanner.build_target(SignIns::Create) do |t| | ||
t.body = "user%3Aemail=test%40test.com&user%3Apassword=1234" | ||
end | ||
scanner.run_check( | ||
scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", | ||
tests: [ | ||
"sqli", # Testing for SQL Injection issues (https://docs.neuralegion.com/docs/sql-injection) | ||
"osi", | ||
"xss", | ||
], | ||
target: target | ||
) | ||
end | ||
end | ||
|
||
it "tests the sign_up page for dom based XSS" do | ||
scan_with_cleanup do |scanner| | ||
target = scanner.build_target(SignUps::New) | ||
scanner.run_check( | ||
scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", | ||
tests: "dom_xss", | ||
target: target | ||
) | ||
end | ||
end | ||
|
||
it "tests the sign_up page for ALL attacks" do | ||
scan_with_cleanup do |scanner| | ||
target = scanner.build_target(SignUps::Create) do |t| | ||
t.body = "user%3Aemail=aa%40aa.com&user%3Apassword=123456789&user%3Apassword_confirmation=123456789" | ||
end | ||
scanner.run_check( | ||
scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", | ||
tests: nil, | ||
target: target | ||
) | ||
end | ||
end | ||
<%- end -%> | ||
it "tests the home page for header, and cookie security issues" do | ||
scan_with_cleanup do |scanner| | ||
target = scanner.build_target(Home::Index) | ||
scanner.run_check( | ||
scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", | ||
severity_threshold: :medium, | ||
tests: [ | ||
"header_security", | ||
"cookie_security" | ||
], | ||
target: target | ||
) | ||
end | ||
end | ||
|
||
it "tests app.js for 3rd party issues" do | ||
scan_with_cleanup do |scanner| | ||
target = SecTester::Target.new(Lucky::RouteHelper.settings.base_uri + Lucky::AssetHelpers.asset("js/app.js")) | ||
scanner.run_check( | ||
scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", | ||
tests: "retire_js", | ||
target: target | ||
) | ||
end | ||
end | ||
<%- else -%> | ||
<%- if generate_auth? -%> | ||
it "tests the sign_in API for SQLi, and JWT attacks" do | ||
scan_with_cleanup do |scanner| | ||
api_headers = HTTP::Headers{"Content-Type" => "application/json", "Accept" => "application/json"} | ||
target = scanner.build_target(Api::SignIns::Create, headers: api_headers) do |t| | ||
t.body = {"user" => {"email" => "aa%40aa.com", "password" => "123456789"}}.to_json | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jwoertink as this is a JSON API call, do we actually need to encode the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably not.... |
||
end | ||
scanner.run_check( | ||
scan_name: "ref: #{ENV["GITHUB_REF"]?} commit: #{ENV["GITHUB_SHA"]?} run id: #{ENV["GITHUB_RUN_ID"]?}", | ||
tests: [ | ||
"sqli", # Testing for SQL Injection issues (https://docs.neuralegion.com/docs/sql-injection) | ||
"jwt", # Testing JWT usage (https://docs.neuralegion.com/docs/broken-jwt-authentication) | ||
"xss", # Checking for Cross Site Scripting attacks (https://docs.neuralegion.com/docs/reflective-cross-site-scripting-rxss) | ||
"ssrf", # Checking for SSRF (https://docs.neuralegion.com/docs/server-side-request-forgery-ssrf) | ||
"proto_pollution", # Checking for proto pollution based vulnerabilities (https://docs.neuralegion.com/docs/prototype-pollution) | ||
"full_path_disclosure", # Checking for full path disclourse on api error (https://docs.neuralegion.com/docs/full-path-disclosure) | ||
], | ||
target: target | ||
) | ||
end | ||
end | ||
<%- end -%> | ||
<%- end -%> | ||
end | ||
|
||
private def scan_with_cleanup : Nil | ||
scanner = LuckySecTester.new | ||
yield scanner | ||
ensure | ||
scanner.try &.cleanup | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
require "lucky_sec_tester" | ||
|
||
# Signup for a `NEXTPLOT_TOKEN` at | ||
# [NeuraLegion](https://app.neuralegion.com/signup) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The company name is now called Bright, but as of this comment, the Github org and this URL are still pointed to NeuraLegion... I don't want to confuse people, so this will need to change once the company's name is fully moved over. |
||
# Read more about the SecTester on https://github.com/luckyframework/lucky_sec_tester | ||
LuckySecTester.configure do |setting| | ||
setting.nexploit_token = ENV["NEXPLOIT_TOKEN"] | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
class AppWithSecTesterTemplate < Teeplate::FileTree | ||
directory "#{__DIR__}/../app_with_sec_tester" | ||
|
||
getter? generate_auth, browser | ||
|
||
def initialize(@generate_auth : Bool, @browser : Bool) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was causing this to run on every single commit. It should be a separate PR, but I needed it to quiet down with all the testing.