Practical Secure Coding Workshop
About me
Stefan Streichsbier
@s_streichsbier
GuardRails.io
Move fast, be safe.
What do these companies have in common?
and 100s of others…
They have been hacked!
p0wned!
defaced!
compromised!
Small Excerpt of public Data Breaches
https://en.wikipedia.org/wiki/List_of_data_breaches
A look at some statistics from Verizon
A look at some statistics from Verizon (cont)
The real impact of hacks & breaches
News is full of high-profile breaches that get widespread attention.
But they are not the only target of hackers
43% of all cyber attacks target
small businesses.
60%
of small businesses that are
Hacked go out of business
within 6 months.
1/5
data breaches are the result
of attackers abusing
insecure web applications.
DevSecOps:
How important is it really?
• Agile took us from months to days to deliver software
• DevOps took us from months to minutes to deploy software
• More applications are mission critical
• Now security has become the bottleneck
How do the hackers do it?
The Root of All Evil is?
User Input
Von Neumann architecture vs Harvard architecture
OWASP Top 10
• A1:2017-Injection
• A2:2017-Broken Authentication
• A3:2017-Sensitive Data Exposure
• A4:2017-XML External Entities (XXE)
• A5:2017-Broken Access Control
• A6:2017-Security Misconfiguration
• A7:2017-Cross-Site Scripting (XSS)
• A8:2017-Insecure Deserialization
• A9:2017-Using Components with Known Vulnerabilities
• A10:2017-Insufficient Logging & Monitoring
SQL Injection' OR 1=1 --
PUBLICSECURITY TRAINING, 2018
User input being executed in an SQL
query at runtime.
PUBLICSECURITY TRAINING, 2018
DEFINITION
PUBLICSECURITY TRAINING, 2018
SELECT *
FROM users u
WHERE
u.username='$username'
AND u.password='$password'
This is a contrived example just to demonstrate the principle.
SQL
DON’T DO THIS
Login
Username
Password
Login
Username
Password
PUBLICSECURITY TRAINING, 2018
12345
rich
SELECT *
FROM users u
WHERE
u.username=' '
AND u.password=' '
rich
12345
SQL
Seriously, never build a login page like this.
DON’T DO THIS
PUBLICSECURITY TRAINING, 2018
SELECT *
FROM users u
WHERE
u.username='rich'
AND u.password='12345'
We’ll talk about storing passwords properly later.
SQL
DON’T DO THIS
id username password email
1 rich 12345 rich@pagerduty.com
Login
Username
Password
PUBLICSECURITY TRAINING, 2018
SELECT *
FROM users u
WHERE
u.username=' '
AND u.password=' '
admin
' OR 1=1 --
SQL
DON’T DO THIS
' OR 1=1 --
.admin
PUBLICSECURITY TRAINING, 2018
SELECT *
FROM users u
WHERE
u.username='admin'
AND u.password=''
OR 1=1
SQL
DON’T DO THIS
id username password email
0 admin %MpQ->3.L-5YRail!k}rH$/3~C?[cj.S%K arup@pagerduty.com
PUBLICSECURITY TRAINING, 2018
Login
Username
Password
'; DROP TABLE users --
hahaha
PUBLICSECURITY TRAINING, 2018
https://xkcd.com/327/
Your Turn
https://portal.securecodewarrior.com/#/website-trial/web/injection/sql/
PUBLICSECURITY TRAINING, 2018
Secret Management
Managing, restricting, and auditing
access to secrets.
PUBLIC
SECURITY TRAINING,
2018
DEFINITION
Secrets?
• Tokens.
• API Keys.
• Passwords.
• Certificates.
• Encryption keys.
PUBLICSECURITY TRAINING, 2018
ಠ_ಠ
PUBLICSECURITY TRAINING, 2018
bankConfig = {
accountName = "pagerduty-bizniz-funds"
authToken = "Bz1gtWJp1a4aybiPxFGGD6HxJ6wl0SjqhJ"
routingNumber = "765555276"
}
PSEUDOCODE
DON’T DO THIS
“I need the password for…”
PUBLIC
SECURITY TRAINING,
2018
PUBLIC
SECURITY TRAINING,
2018
Never share secrets over insecure
communication channels.
KEY TAKEAWAY
PUBLICSECURITY TRAINING, 2018
Rich Adams 11:12
hrm… this command doesn’t work
Obviously, I would never ever accidentally paste a real password into Slack.
This is just a contrived example. Honest.
mysql -h prod -u root -pe8Qd0FKVBJuPqEZZP6Z9phvTk prod-customer-pii
… crap, I’m totally gonna get fired.
PUBLICSECURITY TRAINING, 2018
I, [2018-04-10T22:40:26.379647 #14566] INFO -- : [X-Request-Id: 82a6c040-a552-4ea4-a524-ee32f8f8cf27] [Customer-Name: rich-super-awesome-account] Parameters: {"utf8"=>"✓",
"authenticity_token"=>"5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8", "user"=>{"email"=>"rich@pagerduty.com", "password"=>"bluellama", "remember_me"=>"1"}, "commit"=>"Sign In"}
host= prod-web-app-fb655ea3 | source= /pagerduty/logs/production.log | sourcetype= ruby
This is a hypothetical example, you’ll be pleased to know we do actually redact secrets before they get written to our logs.
I, [2018-04-10T22:41:14.345676 #54858] INFO -- : [X-Request-Id: 7ee95481-00d2-4ba5-a670-2517b115e5ad] [Customer-Name: super-large-enterprise-customer] Parameters: {"utf8"=>"✓",
"authenticity_token"=>"972A13CBBE5E845ECB59DACE8E3ECE01450D33F4", "user"=>{"email"=>"billgates@microsoft.com", "password"=>"windowsxp-was-the-best", "remember_me"=>"1"},
"commit"=>"Sign In"}
host= prod-web-app-ab617639 | source= /pagerduty/logs/production.log | sourcetype= ruby
I, [2018-04-10T22:41:14.786543 #36541] INFO -- : [X-Request-Id: e1ecd16e-50e9-4d27-9236-4c5642fc929c] [Customer-Name: small-startup] Parameters: {"utf8"=>"✓",
"authenticity_token"=>"343AFB87DF4A1287422394441FC1D97FEB04370F", "user"=>{"email"=>"hi@twitterforpets.com", "password"=>"o0OitbeQHfCfHq1QeDuEY", "remember_me"=>"1"},
"commit"=>"Sign In"}
host= prod-web-app-ffe6dbac | source= /pagerduty/logs/production.log | sourcetype= ruby
I, [2018-04-10T22:42:01.000256 #19725] INFO -- : [X-Request-Id: 2a97e0d6-9248-43e0-9ec6-66fe01ceebe2] [Customer-Name: internal-pagerduty-account] Parameters: {"utf8"=>"✓",
"authenticity_token"=>"B47F363E2B430C0647F14DEEA3ECED9B0EF300CE", "user"=>{"email"=>"rich@pagerduty.com", "password"=>"i{/"?4{!o96zo+~:TCid`VH[`}
3Cj8D8*Jw$4aw36h@x7hGh6+Di9xTLIf]u2C", "remember_me"=>"1"}, "commit"=>"Sign In"}
host= prod-web-app-671cdb1a | source= /pagerduty/logs/production.log | sourcetype= ruby
I, [2018-04-10T22:42:05.765391 #69475] INFO -- : [X-Request-Id: 3253b841-57dc-4094-8fa6-39b07f9c2858] [Customer-Name: spiderman] Parameters: {"utf8"=>"✓",
"authenticity_token"=>"03D67C263C27A453EF65B29E30334727333CCBCD", "user"=>{"email"=>"pparker@spiderman.net", "password"=>"venom", "remember_me"=>"1"}, "commit"=>"Sign In"}
host= prod-web-app-fb655ea3 | source= /pagerduty/logs/production.log | sourcetype= ruby
PUBLIC
SECURITY TRAINING,
2018
Be mindful of what you log.
KEY TAKEAWAY
And do any sanitizing/redacting before the log is written to disk or uploaded to Splunk.
Your Turn
https://portal.securecodewarrior.com/#/website-trial/web/crypto/exposedkey/ruby/rails
Let’s get our hands dirty
Setup docker
On Windows
https://docs.docker.com/docker-for-windows/insta
On Mac
https://docs.docker.com/docker-for-mac/
Install Burp Suite & Proxy Switchy for Chrome
https://portswigger.net/burp/communitydownload
Install RailsGoat
1. Go to
https://github.com/streichsbaer/Railsgoat
2. Fork it like it’s hot and make it private
3. Clone it locally
`git clone git@github.com:<insertyourname>/railsgoat.git`
4. Build the docker file
`tools/build.sh`
5.Run it
` tools/run.sh `
6. Browse to
http://IP:3000 (not localhost or 127.0.0.1)
Install GuardRails
https://www.guardrails.io
Create your first PR
config/initializers/stripe.rb
Rails.configuration.stripe = {
:publishable_key => 'pk_live_3cC2OUaORT6Sgitt1ltPeEA1’,
:secret_key => 'sk_live_OaASXG1s0xABCp0k5d8AsbaL'
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
Fix your first issue
config/initializers/stripe.rb
Rails.configuration.stripe = {
:publishable_key => ENV['PUBLISHABLE_KEY’],
:secret_key => ENV['SECRET_KEY']
}
Stripe.api_key = Rails.configuration.stripe[:secret_key]
Enable all findings on GuardRails
1. Add the GuardRails file to show all findings.
.guardrails/config.yml
report:
pullRequest:
findings: "onAllFiles”
More information: https://www.guardrails.io/docs/en/configuration#reportpullrequestfindings
2. Let’s have a look at the findings we want to fix.
SQL Injections
What’s next?
• There are many more Secure Code Warrior exercises
• We can look into more OWASP Top 10 vulnerabilities
• Via Pagerduty’s free training
• We can take a look at a real app together
Thank you
Get a curated list of security resources
Consisting of:
• Awesome security lists
• Developer trainings
• List of great security tools
• Security Page templates
• Free digital copy of my book
• the slides
• … and more
Then send an email to:
iwant@guardrails.io

Practical Secure Coding Workshop - {DECIPHER} Hackathon

  • 1.
  • 2.
  • 3.
    What do thesecompanies have in common? and 100s of others…
  • 4.
    They have beenhacked! p0wned! defaced! compromised!
  • 5.
    Small Excerpt ofpublic Data Breaches https://en.wikipedia.org/wiki/List_of_data_breaches
  • 6.
    A look atsome statistics from Verizon
  • 7.
    A look atsome statistics from Verizon (cont)
  • 8.
    The real impactof hacks & breaches News is full of high-profile breaches that get widespread attention. But they are not the only target of hackers 43% of all cyber attacks target small businesses. 60% of small businesses that are Hacked go out of business within 6 months. 1/5 data breaches are the result of attackers abusing insecure web applications.
  • 9.
    DevSecOps: How important isit really? • Agile took us from months to days to deliver software • DevOps took us from months to minutes to deploy software • More applications are mission critical • Now security has become the bottleneck
  • 10.
    How do thehackers do it?
  • 11.
    The Root ofAll Evil is? User Input Von Neumann architecture vs Harvard architecture
  • 12.
    OWASP Top 10 •A1:2017-Injection • A2:2017-Broken Authentication • A3:2017-Sensitive Data Exposure • A4:2017-XML External Entities (XXE) • A5:2017-Broken Access Control • A6:2017-Security Misconfiguration • A7:2017-Cross-Site Scripting (XSS) • A8:2017-Insecure Deserialization • A9:2017-Using Components with Known Vulnerabilities • A10:2017-Insufficient Logging & Monitoring
  • 13.
    SQL Injection' OR1=1 -- PUBLICSECURITY TRAINING, 2018
  • 14.
    User input beingexecuted in an SQL query at runtime. PUBLICSECURITY TRAINING, 2018 DEFINITION
  • 15.
    PUBLICSECURITY TRAINING, 2018 SELECT* FROM users u WHERE u.username='$username' AND u.password='$password' This is a contrived example just to demonstrate the principle. SQL DON’T DO THIS Login Username Password
  • 16.
    Login Username Password PUBLICSECURITY TRAINING, 2018 12345 rich SELECT* FROM users u WHERE u.username=' ' AND u.password=' ' rich 12345 SQL Seriously, never build a login page like this. DON’T DO THIS
  • 17.
    PUBLICSECURITY TRAINING, 2018 SELECT* FROM users u WHERE u.username='rich' AND u.password='12345' We’ll talk about storing passwords properly later. SQL DON’T DO THIS id username password email 1 rich 12345 rich@pagerduty.com
  • 18.
    Login Username Password PUBLICSECURITY TRAINING, 2018 SELECT* FROM users u WHERE u.username=' ' AND u.password=' ' admin ' OR 1=1 -- SQL DON’T DO THIS ' OR 1=1 -- .admin
  • 19.
    PUBLICSECURITY TRAINING, 2018 SELECT* FROM users u WHERE u.username='admin' AND u.password='' OR 1=1 SQL DON’T DO THIS id username password email 0 admin %MpQ->3.L-5YRail!k}rH$/3~C?[cj.S%K arup@pagerduty.com
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
    Managing, restricting, andauditing access to secrets. PUBLIC SECURITY TRAINING, 2018 DEFINITION
  • 25.
    Secrets? • Tokens. • APIKeys. • Passwords. • Certificates. • Encryption keys. PUBLICSECURITY TRAINING, 2018
  • 26.
    ಠ_ಠ PUBLICSECURITY TRAINING, 2018 bankConfig= { accountName = "pagerduty-bizniz-funds" authToken = "Bz1gtWJp1a4aybiPxFGGD6HxJ6wl0SjqhJ" routingNumber = "765555276" } PSEUDOCODE DON’T DO THIS
  • 27.
    “I need thepassword for…” PUBLIC SECURITY TRAINING, 2018
  • 28.
    PUBLIC SECURITY TRAINING, 2018 Never sharesecrets over insecure communication channels. KEY TAKEAWAY
  • 29.
    PUBLICSECURITY TRAINING, 2018 RichAdams 11:12 hrm… this command doesn’t work Obviously, I would never ever accidentally paste a real password into Slack. This is just a contrived example. Honest. mysql -h prod -u root -pe8Qd0FKVBJuPqEZZP6Z9phvTk prod-customer-pii … crap, I’m totally gonna get fired.
  • 30.
    PUBLICSECURITY TRAINING, 2018 I,[2018-04-10T22:40:26.379647 #14566] INFO -- : [X-Request-Id: 82a6c040-a552-4ea4-a524-ee32f8f8cf27] [Customer-Name: rich-super-awesome-account] Parameters: {"utf8"=>"✓", "authenticity_token"=>"5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8", "user"=>{"email"=>"rich@pagerduty.com", "password"=>"bluellama", "remember_me"=>"1"}, "commit"=>"Sign In"} host= prod-web-app-fb655ea3 | source= /pagerduty/logs/production.log | sourcetype= ruby This is a hypothetical example, you’ll be pleased to know we do actually redact secrets before they get written to our logs. I, [2018-04-10T22:41:14.345676 #54858] INFO -- : [X-Request-Id: 7ee95481-00d2-4ba5-a670-2517b115e5ad] [Customer-Name: super-large-enterprise-customer] Parameters: {"utf8"=>"✓", "authenticity_token"=>"972A13CBBE5E845ECB59DACE8E3ECE01450D33F4", "user"=>{"email"=>"billgates@microsoft.com", "password"=>"windowsxp-was-the-best", "remember_me"=>"1"}, "commit"=>"Sign In"} host= prod-web-app-ab617639 | source= /pagerduty/logs/production.log | sourcetype= ruby I, [2018-04-10T22:41:14.786543 #36541] INFO -- : [X-Request-Id: e1ecd16e-50e9-4d27-9236-4c5642fc929c] [Customer-Name: small-startup] Parameters: {"utf8"=>"✓", "authenticity_token"=>"343AFB87DF4A1287422394441FC1D97FEB04370F", "user"=>{"email"=>"hi@twitterforpets.com", "password"=>"o0OitbeQHfCfHq1QeDuEY", "remember_me"=>"1"}, "commit"=>"Sign In"} host= prod-web-app-ffe6dbac | source= /pagerduty/logs/production.log | sourcetype= ruby I, [2018-04-10T22:42:01.000256 #19725] INFO -- : [X-Request-Id: 2a97e0d6-9248-43e0-9ec6-66fe01ceebe2] [Customer-Name: internal-pagerduty-account] Parameters: {"utf8"=>"✓", "authenticity_token"=>"B47F363E2B430C0647F14DEEA3ECED9B0EF300CE", "user"=>{"email"=>"rich@pagerduty.com", "password"=>"i{/"?4{!o96zo+~:TCid`VH[`} 3Cj8D8*Jw$4aw36h@x7hGh6+Di9xTLIf]u2C", "remember_me"=>"1"}, "commit"=>"Sign In"} host= prod-web-app-671cdb1a | source= /pagerduty/logs/production.log | sourcetype= ruby I, [2018-04-10T22:42:05.765391 #69475] INFO -- : [X-Request-Id: 3253b841-57dc-4094-8fa6-39b07f9c2858] [Customer-Name: spiderman] Parameters: {"utf8"=>"✓", "authenticity_token"=>"03D67C263C27A453EF65B29E30334727333CCBCD", "user"=>{"email"=>"pparker@spiderman.net", "password"=>"venom", "remember_me"=>"1"}, "commit"=>"Sign In"} host= prod-web-app-fb655ea3 | source= /pagerduty/logs/production.log | sourcetype= ruby
  • 31.
    PUBLIC SECURITY TRAINING, 2018 Be mindfulof what you log. KEY TAKEAWAY And do any sanitizing/redacting before the log is written to disk or uploaded to Splunk.
  • 32.
  • 33.
    Let’s get ourhands dirty
  • 34.
  • 35.
    Install Burp Suite& Proxy Switchy for Chrome https://portswigger.net/burp/communitydownload
  • 36.
    Install RailsGoat 1. Goto https://github.com/streichsbaer/Railsgoat 2. Fork it like it’s hot and make it private 3. Clone it locally `git clone git@github.com:<insertyourname>/railsgoat.git` 4. Build the docker file `tools/build.sh` 5.Run it ` tools/run.sh ` 6. Browse to http://IP:3000 (not localhost or 127.0.0.1)
  • 37.
  • 38.
    Create your firstPR config/initializers/stripe.rb Rails.configuration.stripe = { :publishable_key => 'pk_live_3cC2OUaORT6Sgitt1ltPeEA1’, :secret_key => 'sk_live_OaASXG1s0xABCp0k5d8AsbaL' } Stripe.api_key = Rails.configuration.stripe[:secret_key]
  • 39.
    Fix your firstissue config/initializers/stripe.rb Rails.configuration.stripe = { :publishable_key => ENV['PUBLISHABLE_KEY’], :secret_key => ENV['SECRET_KEY'] } Stripe.api_key = Rails.configuration.stripe[:secret_key]
  • 40.
    Enable all findingson GuardRails 1. Add the GuardRails file to show all findings. .guardrails/config.yml report: pullRequest: findings: "onAllFiles” More information: https://www.guardrails.io/docs/en/configuration#reportpullrequestfindings 2. Let’s have a look at the findings we want to fix. SQL Injections
  • 41.
    What’s next? • Thereare many more Secure Code Warrior exercises • We can look into more OWASP Top 10 vulnerabilities • Via Pagerduty’s free training • We can take a look at a real app together
  • 42.
  • 43.
    Get a curatedlist of security resources Consisting of: • Awesome security lists • Developer trainings • List of great security tools • Security Page templates • Free digital copy of my book • the slides • … and more Then send an email to: iwant@guardrails.io

Editor's Notes

  • #5 DevOps is all about breaking down barriers, have developers work with the business, with the ops team and simply out-innovate and out-ship the competition. Software has become mission-critical!
  • #9 While hacking-related data breaches and subsequent ransom demands to large corporations like HBO, Target, and Home Depot understandably garner widespread attention, t he resulting assumption that only large companies face this growing digital threat couldn’t be further from the truth. In fact, a study in 2016 found that 43% of all cyber attacks targeted small businesses. Even more alarming is that a staggering 60% of small businesses hit with a cyber attack or data breach go out of business within 6 months. Software has become mission-critical!
  • #10 DevOps is all about breaking down barriers, have developers work with the business, with the ops team and simply out-innovate and out-ship the competition. Software has become mission-critical!
  • #14 OK, let's get started with some actual technical content. Our first main topic is SQL injection.
  • #15 Let's take a look at a quick example, using the query for a hypothetical (and very bad) login page. Seriously, never design a login page like this, I'm just using this as a contrived example to demonstrate. When logging in, this will lookup the user record based on the username and password that is entered. If a result is returned, it will log that person in. Pretty simple, and there are actually login pages out there that work this way (unfortunately).
  • #16 Let's take a look at a quick example, using the query for a hypothetical (and very bad) login page. Seriously, never design a login page like this, I'm just using this as a contrived example to demonstrate. When logging in, this will lookup the user record based on the username and password that is entered. If a result is returned, it will log that person in. Pretty simple, and there are actually login pages out there that work this way (unfortunately).
  • #17 So let's login with a real user to see how this works under normal conditions. The username and password get put into the query, which will then execute using those values.
  • #18 The SQL statement is valid. The username and password are correct, so a single result is returned for the user, and they would now be logged in as this user. The keen eyed amongst you will have spotted that passwords should never be stored this way. We'll talk about properly storing passwords later. Remember, there's a big red icon in the corner here, never implement a login page like this! OK, so that's all well and good. That's how the developer intended it to work.
  • #19 But honest people aren't always going to be the ones using such a login form. Some users will be attackers, and they won't play by the rules. So let's say we have an attacker, and they now enter something like this instead. They have a username of admin, but a password of ' OR 1=1 --. As before, the username and password get replaced in the SQL statement. But something different has happened here. Because this code is susceptible to SQL injection, the query being executed has actually changed from what the developer wanted. You can see in the red box here that the SQL query is now different.
  • #20 This new SQL statement has an extra condition in it, which means this query will return the row for the admin user, even though the correct password wasn't entered. The query added an OR 1=1, which will always evaluate to true (since 1 is always equal to 1). Since OR true will always be true, it doesn't matter what else the user entered, they will automatically get the correct result. This user would now be logged in as an administrator even though they didn't know the password. That's not great.
  • #21 This can get out of hand very quickly. Hopefully you can start to imagine other ways in which this could be dangerous if your code is susceptible to SQL injection.
  • #22 You may have come across this XKCD comic before, about a boy called Little Bobby Tables. If you didn't know what SQL injection was before, you should hopefully now start to have an idea of what's going on here.
  • #25 What does that mean? Well, secret management is all about protecting and auditing access to secrets. We want to make sure that no one evil can look at our secrets, but that if they do we have a record of it. We also want to know who's looking at our secrets, even if they're allowed to.
  • #26 But what do we mean by "secrets"? The best way to manage a secret is to not have one in the first place. But that isn't always possible. A decent rule of thumb is that anything with the words "token", "key", "password", or "secret" in the name should be considered a secret. That doesn't cover all cases, but most things fall under those categories.
  • #27 What we absolutely don't want is secrets hardcoded into our source code. It can be tempting to hardcode things like this, but it's never a good idea. The reason this is bad is that anyone with access to the source code gets access to the secret. Generally, the developers building the software don't need to know the secrets that are used to operate that software. Ideally, you want all that to be automated with humans never even seeing the secrets at all. But at the very least, you want the secrets decoupled from the source code.
  • #28 On the subject of secrets, I occasionally see messages like this in Slack: "I need the password for..." We should try and get out of this habit, as it not only assumes that we have a shared password for everything (which obviously isn't the case), but it's subconsciously encouraging passwords to be sent over Slack. Very rarely is there a "password" for something that needs to be shared. We should all have individual accounts to things so that we have accountability. So the question should really be "I need access to..." instead. Even then, if a secret needs to be shared, it needs to be done the correct way.
  • #29 Remember that secrets should never be shared over insecure communication channels. Slack is an insecure communication channel, so is email. If there's a secret that needs to be shared, it should be in Vault, or in 1Password, or some other dedicated secure secret delivery tool.
  • #30 But what happens if you do it accidentally? As shown in this completely made up and totally not real scenario. It can happen, you had something in your clipboard and paste without realizing. By the time you hit enter and spot it, it's too late. Well, don't panic. We all make mistakes. You're not going to get into trouble. I've accidentally posted secrets in chat tools before, I'm sure most people have. What matters is what you do next...
  • #31 Another part of managing secrets is to make sure they never appear in places they shouldn't. Logs are typically where this happens by accident. You enable some sort of debug-level logging, and all of a sudden tokens, API keys, and passwords start appearing in log files. Even worse, they're not passwords we control, so we can't just rotate them. They're likely to be customer passwords. Which means we'd have to notify those customers to change their credentials. We have automation in place to redact anything that even remotely looks like a secret, but it's not perfect and you shouldn't rely on it.
  • #32 Be mindful of what you're logging, and if it's a secret, don't log it. If you need to do any sanitizing, make sure it happens before the log is written to disk or uploaded to our centralized logging tools.