SlideShare ist ein Scribd-Unternehmen logo
1 von 49
Odoo Code Hardening
- Security -
Software Security
is hard.
Intent changes the
odds.
Knowledge and
mindset are key.
Security Model
Business
Data
RBAC = Groups + ACL + Rules
Apps / Business Logic
Access
Control
RISKS?
TOP 10
A1. Injection A6. Security Misconfiguration
A2. Broken Authentication A7. Cross-Site Scripting (XSS)
A3. Sensitive Data Exposure A8. Insecure Deserialization
A4. XML External Entities (XXE) A9. Vulnerable Components
A5. Broken Access Control A10. Insufficient Logging
(2017 ed.)
HELP?
The Odoo framework includes a lot of
mechanisms to avoid mistakes.
But knowledge and mindset are key!
A1. Injection
Untrusted data interpreted as code
Hello, my name is
Robert’); DROP TABLE students;--
👱
https://xkcd.com/327
# SQL Injection (simplified)
def _get_partner_match(self, name, partner_type='is_customer'):
query = f"""SELECT id FROM res_partner
WHERE name ILIKE '%{name}%'
AND {partner_type} IS TRUE"""
self._cr.execute(query)
return self._cr.fetchall()
# SQL Injection (simplified) - 2
def _get_partner_match(self, name, partner_type='is_customer'):
query = f"""SELECT id FROM res_partner
WHERE name ILIKE '%%%(name)s%%'
AND {partner_type} IS TRUE """
self._cr.execute(query, (name,))
return self._cr.fetchall()
# SQL Injection (simplified) - 3 - Safe!
def _get_partner_match(self, name, partner_type='is_customer'):
if partner_type not in ('is_customer', 'is_supplier'):
raise ValueError()
query = f"""SELECT id FROM res_partner
WHERE name ILIKE '%%%(name)s%%'
AND {partner_type} IS TRUE """
self._cr.execute(query, (name,))
return self._cr.fetchall()
# Best option when possible: use the ORM
def _get_partner_match(self, name, partner_type='is_customer'):
return self.search([('name', 'ilike', name),
(partner_type, '=', True)])
A2. Broken Auth
Authentication / session management
logic error
A2. Broken Auth
Bad news: there are lots of moving
parts, it’s hard to get this right.
Good news: the system does all of
that for you.
Be very careful if you try to modify or
extend the authentication and session
mechanisms.
➔ Securing session cookie
➔ Preventing session injection
➔ Rotating session after login/logout
➔ Storing passwords securely
➔ Verifying passwords securely
➔ Preventing brute-force attacks
➔ Security of password reset flow
➔ Rejecting deactivated users
➔ Instant lockout after account change
➔ Integration with third-party auths
➔ Two-factor flow, token security
➔ ...
and much more...
What’s so hard?
A3. Sensitive Data
Exposure
Insufficient protection for sensitive data
TODO
# Sensitive data exposed
class Employee(models.Model):
_inherit = "hr.employee"
ssnid = fields.Char("Social Security Number")
passport = fields.Char("Passport No")
# Sensitive data protected
class Employee(models.Model):
_inherit = "hr.employee"
ssnid = fields.Char("Social Security Number", groups="hr.group_officer")
passport = fields.Char("Passport No", groups="hr.group_officer")
A4. XML External
Entities
Unsafe parsing of untrusted XML data
XXE: use safe XML parsers
Recursion bombs
<!DOCTYPE xmlbomb [
<!ENTITY a "1234567890" >
<!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;">
<!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;">
<!ENTITY d "&c;&c;&c;&c;&c;&c;&c;&c;">
]>
<bomb>&d;</bomb>
Local File Inclusion
<!DOCTYPE external [
<!ENTITY ee SYSTEM "file:///etc/password">
]>
<root>&ee;</root>
The framework protects you.
Use lxml.etree:
etree.fromstring(xml_data)
lxml.etree is configured to reject:
+ recursive entities
+ network resolution
+ local entity resolution
Or have a look at defusedxml.
A5. Broken Access
Control
Incorrect validation of user permissions
# Missing/Incorrect ACLs
➔ The most common mistake!
➔ New models require:
+ ACLs (CRUD)
+ Record rules (CRUD filter)
+ Field-level permission
Bad ACLs examples
# Full Access to everyone - incorrect
id,model_id,group_id,p_read,p_write,p_create,p_unlink
access_my_model,model_my_model, ,1,1,1,1
# Full Access to employees - probably incorrect
id,model_id,group_id,p_read,p_write,p_create,p_unlink
access_my_model,model_my_model,base.group_user,1,1,1,1
Normal ACLs examples
# Employee = Read | Manager = Full
id,model_id,group_id,p_read,p_write,p_create,p_unlink
access_my_model,model_my_model,base.group_user,1,0,0,0
access_my_model,model_my_model,base.group_manager,1,1,1,1
As of V14, also for TransientModel.
# Incorrect sudo() or permission test
# Portal controller route
@route(['/sale/<int:order_id>/approve'], type='json', methods=['POST'], auth='public')
def order_approve(self, order_id, **post):
order = self.env['sale.order'].sudo().browse(order_id)
order.action_approve()
user
public
none
converters type methods
auth
# Incorrect sudo() or permission test
# Portal controller route - bad!
@route(['/sale/<int:order_id>/approve'], type='json', methods=['POST'], auth='public')
def order_approve(self, order_id, **post):
order = self.env['sale.order'].sudo().browse(order_id)
order.action_approve()
# Incorrect sudo() or permission test
# Portal controller route - corrected
@route(['/sale/<int:order_id>/approve'], type='http', methods=['POST'], auth='public')
def order_approve(self, order_id, token, **post):
order = self.env['sale.order'].sudo().browse(order_id)
if not tools.consteq(order.access_token, token):
raise AccessDenied()
order.action_approve()
# Incorrect sudo() or permission test
def get_notifications(self, partner_id):
# direct SQL for complex query performance
query = """
SELECT DISTINCT m.id, m.author_id, m.message_type
FROM mail_message
LEFT JOIN mail_message_res_partner_rel
LEFT JOIN mail_message_res_partner_needaction_rel needaction
(...)
WHERE partner_id = %s
"""
self._cr.execute(query, (partner_id,))
return self._cr.fetchall()
# Incorrect sudo() or permission test
def _get_notifications(self, partner_id):
self.check_access_rights('read')
# direct SQL for complex query performance
query = """
SELECT DISTINCT m.id, m.author_id, m.message_type
FROM mail_message
LEFT JOIN mail_message_res_partner_rel
LEFT JOIN mail_message_res_partner_needaction_rel needaction
(...)
WHERE partner_id = %s
"""
self._cr.execute(query, (partner_id,))
return self._cr.fetchall()
A6. Security
Misconfiguration
odoo.com/documentatio
n ● PostgreSQL security (no super user)
● Web server + TLS
● Database manager security
● Separate Production / Staging / Dev
● No demo data on Production
● SSH security
● Rate-limiting and brute-force
protections
And more...
Deployment Checklist
A7. XSS
Untrusted data interpreted as code… again!
Stored / Reflected XSS
➔ Untrusted HTML content in the database,
in some text/char field
➔ Victim is tricked into viewing it
➔ When displayed in the browser, it
becomes executable
@route('/index', type='http', auth="none")
def index(self)
session_info = {
'user_name': request.env.user.name,
}
response = request.render(
'web.webclient_bootstrap',
{session_info: session_info}
)
return response
<template id="web.webclient_bootstrap">
<t t-call="web.layout">
<t t-set="head_web">
<script type="text/javascript">
odoo.session_info =
<t t-raw="str(session_info)"/>;
</script>
</t>
</t>
</template>
Name:
</script><script>alert(document.cookie);//
<script type="text/javascript">
odoo.session_info = {'user_name':
"</script><script>alert(document.cookie);//"};
</script>
Stored / Reflected XSS
➔ Untrusted HTML content in the database,
in some text/char field
➔ Victim is tricked into viewing it
➔ When displayed in the browser, it
does not become executable
@route('/index', type='http', auth="none")
def index(self)
session_info = {
'user_name': request.env.user.name,
}
response = request.render(
'web.webclient_bootstrap',
{session_info: session_info}
)
return response
<template id="web.webclient_bootstrap">
<t t-call="web.layout">
<t t-set="head_web">
<script type="text/javascript">
odoo.session_info =
<t t-esc="str(session_info)"/>;
</script>
</t>
</t>
</template>
Name:
</script><script>alert(document.cookie);//
<script type="text/javascript">
odoo.session_info = {'user_name':
'&lt;/script&gt;&lt;script&gt;alert(document.cookie);//'};
</script>
DOM-based XSS
Barrier broken between text and markup
// Text manipulation
elem.textContent = "...";
$elem.text(“..”);
// Markup manipulation
elem.innerHTML = ""...";
$elem.html(...);
Do not mix them.
/**
* Adds the product description based on attribute values
*
* @private
*/
_postProcessContent: function ($modalContent) {
var $productDescription = $modalContent
.find('.main_product');
var desc = $productDescription.html();
$.each(this.rootProduct.attribute_values, function () {
desc += ('<br/>' + this.attribute_value_name
+ ':' + this.custom_value);
});
$productDescription.html(desc);
return $modalContent;
},
DOM XSS
Barrier broken between text and markup
// Text manipulation
elem.textContent = "...";
$elem.text(“..”);
// Markup manipulation
elem.innerHTML = ""...";
$elem.html(...);
Do not mix.
Maybe convert.
markup = _.escape(text);
/**
* Adds the product description based on attribute values
*
* @private
*/
_postProcessContent: function ($modalContent) {
var $productDescription = $modalContent
.find('.main_product');
var desc = $productDescription.html();
$.each(this.rootProduct.attribute_values, function () {
desc += ('<br/>' + _.escape(this.attribute_value_name)
+ ':' + _.escape(this.custom_value));
});
$productDescription.html(desc);
return $modalContent;
},
DOM XSS
Barrier broken between text and markup
// Text manipulation
elem.textContent = "...";
$elem.text(“..”);
// Markup manipulation
elem.innerHTML = ""...";
$elem.html(...);
Do not mix.
Maybe convert.
But, really: do not mix.
/**
* Adds the product description based on attribute values
*
* @private
*/
_postProcessContent: function ($modalContent) {
var $productDescription = $modalContent
.find('.main_product');
var $customValuesDescription = $('<div>');
$.each(this.rootProduct.attribute_values, function () {
$customValuesDescription.append($('<div>', {
text: (this.attribute_value_name + ': ' +
this.custom_value);
}));
});
$productDescription.append($customValuesDescription);
return $modalContent;
},
STRING
FORMATTING
“<b>” + name
`<b>${name}</b>`
UNSAFE
DESERIALIZATION
eval()
VULNERABLE
TEMPLATES
t-raw
VULNERABLE LIB
$.popover()
FILES
.svg,.html
LINKS
javascript:
XSS VECTORS ARE EVERYWHERE
A8. Insecure
Deserialization
The framework uses safe serialization:
● RPC protocols (JSON-RPC, XML-RPC)
● Cache
● Cookies, sessions
● Signed structured data
So watch out:
● Don’t use pickle, use JSON!
● Don’t parse data with eval()
● Sign structured data
A9. Vulnerable
Components
A10. Insufficient
Logging
@classmethod
def _login(cls, db, login, password, user_agent_env):
ip = request.httprequest.environ['REMOTE_ADDR'] if request else 'n/a'
try:
# do login ...
except AccessDenied:
_logger.info("Login failed for db:%s login:%s from %s", db, login, ip)
raise
_logger.info("Login successful for db:%s login:%s from %s", db, login, ip)
_logger.info(
"Password reset attempt for <%s> by user <%s> from %s",
login, request.env.user.login, request.httprequest.remote_addr)
odoo.addons.base.models.res_users: Login failed for db:production login:mike@ex.com from 16.12.19.27
odoo.addons.base.models.res_users: Login successful for db:production login:mike@ex.com from 14.16.23.56
odoo.addons.auth_signup...main: Password reset attempt for <lenny@ex.com> by user <public> from 85.133.187.167
def assert_log_admin_access(method):
"""Decorator checking that the calling user is an administrator, and logging the call.
Raise an AccessDenied error if the user does not have administrator privileges
"""
def check_and_log(method, self, *args, **kwargs):
user = self.env.user
origin = request.httprequest.remote_addr if request else 'n/a'
log_data = (method.__name__, self.sudo().mapped('name'), user.login, user.id, origin)
if not self.env.is_admin():
_logger.warning('DENY access to module.%s on %s to user %s ID #%s via %s', *log_data)
raise AccessDenied()
_logger.info('ALLOW access to module.%s on %s to user %s #%s via %s', *log_data)
return method(self, *args, **kwargs)
return decorator(check_and_log, method)
odoo...ir_module: ALLOW access to module.button_immediate_uninstall on ['crm'] to user bart@ex.com #2 via 2.5.15.214
odoo...ir_module: ALLOW access to module.button_uninstall on ['crm'] to user bart@ex.com #2 via 2.5.15.214
odoo...ir_module: ALLOW access to module.module_uninstall on ['sale_crm', 'crm'] to user __system__ #1 via 2.5.15.214
CODE
REVIEW
CHECKLIST
01
CONTROL
ACCESS
Groups, ACLs, Rules
and Fields
02
VERIFY
PERMISSIONS
sudo(), controllers,
private methods
03
CHECK TEMPLATES
t-raw, untrusted
input escaped
04
SAFE EVAL
Eval only trusted input,
iff impossible to avoid
BLOCK INJECTIONS
05 Double-check raw SQL,
shell commands, etc.
XSS PREVENTION
06 DOM, Stored,
Reflected, look for the
signs!
Choose someone who
improves the knowledge
and mindset of the team.
Thank You

Weitere ähnliche Inhalte

Was ist angesagt?

OpenERP Technical Memento
OpenERP Technical MementoOpenERP Technical Memento
OpenERP Technical Memento
Odoo
 
Mastering PostgreSQL Administration
Mastering PostgreSQL AdministrationMastering PostgreSQL Administration
Mastering PostgreSQL Administration
Command Prompt., Inc
 

Was ist angesagt? (20)

Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)
Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)
Odoo Experience 2018 - How to Break Odoo Security (or how to prevent it)
 
Simple Odoo ERP auto scaling on AWS
Simple Odoo ERP auto scaling on AWSSimple Odoo ERP auto scaling on AWS
Simple Odoo ERP auto scaling on AWS
 
Common Performance Pitfalls in Odoo apps
Common Performance Pitfalls in Odoo appsCommon Performance Pitfalls in Odoo apps
Common Performance Pitfalls in Odoo apps
 
Owl: The New Odoo UI Framework
Owl: The New Odoo UI FrameworkOwl: The New Odoo UI Framework
Owl: The New Odoo UI Framework
 
Odoo External API
Odoo External APIOdoo External API
Odoo External API
 
Odoo's Test Framework - Learn Best Practices
Odoo's Test Framework - Learn Best PracticesOdoo's Test Framework - Learn Best Practices
Odoo's Test Framework - Learn Best Practices
 
Odoo Code Hardening [Odoo Experience 2019]
Odoo Code Hardening [Odoo Experience 2019]Odoo Code Hardening [Odoo Experience 2019]
Odoo Code Hardening [Odoo Experience 2019]
 
Impact of the New ORM on Your Modules
Impact of the New ORM on Your ModulesImpact of the New ORM on Your Modules
Impact of the New ORM on Your Modules
 
An in Depth Journey into Odoo's ORM
An in Depth Journey into Odoo's ORMAn in Depth Journey into Odoo's ORM
An in Depth Journey into Odoo's ORM
 
Object Relation Mapping in Odoo 16
Object Relation Mapping in Odoo 16Object Relation Mapping in Odoo 16
Object Relation Mapping in Odoo 16
 
Developing New Widgets for your Views in Owl
Developing New Widgets for your Views in OwlDeveloping New Widgets for your Views in Owl
Developing New Widgets for your Views in Owl
 
Asynchronous JS in Odoo
Asynchronous JS in OdooAsynchronous JS in Odoo
Asynchronous JS in Odoo
 
OpenERP Technical Memento
OpenERP Technical MementoOpenERP Technical Memento
OpenERP Technical Memento
 
Mastering PostgreSQL Administration
Mastering PostgreSQL AdministrationMastering PostgreSQL Administration
Mastering PostgreSQL Administration
 
Odoo Experience 2018 - Code Profiling in Odoo
Odoo Experience 2018 - Code Profiling in OdooOdoo Experience 2018 - Code Profiling in Odoo
Odoo Experience 2018 - Code Profiling in Odoo
 
The Odoo JS Framework
The Odoo JS FrameworkThe Odoo JS Framework
The Odoo JS Framework
 
Discover GraphQL with Python, Graphene and Odoo
Discover GraphQL with Python, Graphene and OdooDiscover GraphQL with Python, Graphene and Odoo
Discover GraphQL with Python, Graphene and Odoo
 
아라한사의 스프링 시큐리티 정리
아라한사의 스프링 시큐리티 정리아라한사의 스프링 시큐리티 정리
아라한사의 스프링 시큐리티 정리
 
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ BehaviourWAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
WAF Bypass Techniques - Using HTTP Standard and Web Servers’ Behaviour
 
XSS Magic tricks
XSS Magic tricksXSS Magic tricks
XSS Magic tricks
 

Ähnlich wie Security: Odoo Code Hardening

PCI Security Requirements - secure coding
PCI Security Requirements - secure codingPCI Security Requirements - secure coding
PCI Security Requirements - secure coding
Haitham Raik
 
Php & Web Security - PHPXperts 2009
Php & Web Security - PHPXperts 2009Php & Web Security - PHPXperts 2009
Php & Web Security - PHPXperts 2009
mirahman
 
12-security.ppt - PHP and Arabic Language - Index
12-security.ppt - PHP and Arabic Language - Index12-security.ppt - PHP and Arabic Language - Index
12-security.ppt - PHP and Arabic Language - Index
webhostingguy
 
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core
NETFest
 
ASP.Net Presentation Part3
ASP.Net Presentation Part3ASP.Net Presentation Part3
ASP.Net Presentation Part3
Neeraj Mathur
 

Ähnlich wie Security: Odoo Code Hardening (20)

PCI Security Requirements - secure coding
PCI Security Requirements - secure codingPCI Security Requirements - secure coding
PCI Security Requirements - secure coding
 
Php Security By Mugdha And Anish
Php Security By Mugdha And AnishPhp Security By Mugdha And Anish
Php Security By Mugdha And Anish
 
Php & Web Security - PHPXperts 2009
Php & Web Security - PHPXperts 2009Php & Web Security - PHPXperts 2009
Php & Web Security - PHPXperts 2009
 
Security in Node.JS and Express:
Security in Node.JS and Express:Security in Node.JS and Express:
Security in Node.JS and Express:
 
Applications secure by default
Applications secure by defaultApplications secure by default
Applications secure by default
 
Applications secure by default
Applications secure by defaultApplications secure by default
Applications secure by default
 
Rails Security
Rails SecurityRails Security
Rails Security
 
ASP.NET Web Security
ASP.NET Web SecurityASP.NET Web Security
ASP.NET Web Security
 
Web Security 101
Web Security 101Web Security 101
Web Security 101
 
Let's write secure Drupal code! - DrupalCamp London 2019
Let's write secure Drupal code! - DrupalCamp London 2019Let's write secure Drupal code! - DrupalCamp London 2019
Let's write secure Drupal code! - DrupalCamp London 2019
 
10 Rules for Safer Code
10 Rules for Safer Code10 Rules for Safer Code
10 Rules for Safer Code
 
Secure Coding for NodeJS
Secure Coding for NodeJSSecure Coding for NodeJS
Secure Coding for NodeJS
 
The top 10 security issues in web applications
The top 10 security issues in web applicationsThe top 10 security issues in web applications
The top 10 security issues in web applications
 
10 Rules for Safer Code [Odoo Experience 2016]
10 Rules for Safer Code [Odoo Experience 2016]10 Rules for Safer Code [Odoo Experience 2016]
10 Rules for Safer Code [Odoo Experience 2016]
 
Hacking 101 (Session 2)
Hacking 101  (Session 2)Hacking 101  (Session 2)
Hacking 101 (Session 2)
 
12-security.ppt - PHP and Arabic Language - Index
12-security.ppt - PHP and Arabic Language - Index12-security.ppt - PHP and Arabic Language - Index
12-security.ppt - PHP and Arabic Language - Index
 
Security.ppt
Security.pptSecurity.ppt
Security.ppt
 
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core
.NET Fest 2017. Михаил Щербаков. Механизмы предотвращения атак в ASP.NET Core
 
ASP.Net Presentation Part3
ASP.Net Presentation Part3ASP.Net Presentation Part3
ASP.Net Presentation Part3
 
XSS
XSSXSS
XSS
 

Mehr von Odoo

Mehr von Odoo (20)

Timesheet Workshop: The Timesheet App People Love!
Timesheet Workshop: The Timesheet App People Love!Timesheet Workshop: The Timesheet App People Love!
Timesheet Workshop: The Timesheet App People Love!
 
Odoo 3D Product View with Google Model-Viewer
Odoo 3D Product View with Google Model-ViewerOdoo 3D Product View with Google Model-Viewer
Odoo 3D Product View with Google Model-Viewer
 
Keynote - Vision & Strategy
Keynote - Vision & StrategyKeynote - Vision & Strategy
Keynote - Vision & Strategy
 
Opening Keynote - Unveilling Odoo 14
Opening Keynote - Unveilling Odoo 14Opening Keynote - Unveilling Odoo 14
Opening Keynote - Unveilling Odoo 14
 
Extending Odoo with a Comprehensive Budgeting and Forecasting Capability
Extending Odoo with a Comprehensive Budgeting and Forecasting CapabilityExtending Odoo with a Comprehensive Budgeting and Forecasting Capability
Extending Odoo with a Comprehensive Budgeting and Forecasting Capability
 
Managing Multi-channel Selling with Odoo
Managing Multi-channel Selling with OdooManaging Multi-channel Selling with Odoo
Managing Multi-channel Selling with Odoo
 
Product Configurator: Advanced Use Case
Product Configurator: Advanced Use CaseProduct Configurator: Advanced Use Case
Product Configurator: Advanced Use Case
 
Accounting Automation: How Much Money We Saved and How?
Accounting Automation: How Much Money We Saved and How?Accounting Automation: How Much Money We Saved and How?
Accounting Automation: How Much Money We Saved and How?
 
Rock Your Logistics with Advanced Operations
Rock Your Logistics with Advanced OperationsRock Your Logistics with Advanced Operations
Rock Your Logistics with Advanced Operations
 
Transition from a cost to a flow-centric organization
Transition from a cost to a flow-centric organizationTransition from a cost to a flow-centric organization
Transition from a cost to a flow-centric organization
 
Synchronization: The Supply Chain Response to Overcome the Crisis
Synchronization: The Supply Chain Response to Overcome the CrisisSynchronization: The Supply Chain Response to Overcome the Crisis
Synchronization: The Supply Chain Response to Overcome the Crisis
 
Running a University with Odoo
Running a University with OdooRunning a University with Odoo
Running a University with Odoo
 
Down Payments on Purchase Orders in Odoo
Down Payments on Purchase Orders in OdooDown Payments on Purchase Orders in Odoo
Down Payments on Purchase Orders in Odoo
 
Odoo Implementation in Phases - Success Story of a Retail Chain 3Sach food
Odoo Implementation in Phases - Success Story of a Retail Chain 3Sach foodOdoo Implementation in Phases - Success Story of a Retail Chain 3Sach food
Odoo Implementation in Phases - Success Story of a Retail Chain 3Sach food
 
Migration from Salesforce to Odoo
Migration from Salesforce to OdooMigration from Salesforce to Odoo
Migration from Salesforce to Odoo
 
Preventing User Mistakes by Using Machine Learning
Preventing User Mistakes by Using Machine LearningPreventing User Mistakes by Using Machine Learning
Preventing User Mistakes by Using Machine Learning
 
Becoming an Odoo Expert: How to Prepare for the Certification
Becoming an Odoo Expert: How to Prepare for the Certification Becoming an Odoo Expert: How to Prepare for the Certification
Becoming an Odoo Expert: How to Prepare for the Certification
 
Instant Printing of any Odoo Report or Shipping Label
Instant Printing of any Odoo Report or Shipping LabelInstant Printing of any Odoo Report or Shipping Label
Instant Printing of any Odoo Report or Shipping Label
 
How Odoo helped an Organization Grow 3 Fold
How Odoo helped an Organization Grow 3 FoldHow Odoo helped an Organization Grow 3 Fold
How Odoo helped an Organization Grow 3 Fold
 
From Shopify to Odoo
From Shopify to OdooFrom Shopify to Odoo
From Shopify to Odoo
 

Kürzlich hochgeladen

FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
dollysharma2066
 
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
amitlee9823
 
Russian Call Girls In Rajiv Chowk Gurgaon ❤️8448577510 ⊹Best Escorts Service ...
Russian Call Girls In Rajiv Chowk Gurgaon ❤️8448577510 ⊹Best Escorts Service ...Russian Call Girls In Rajiv Chowk Gurgaon ❤️8448577510 ⊹Best Escorts Service ...
Russian Call Girls In Rajiv Chowk Gurgaon ❤️8448577510 ⊹Best Escorts Service ...
lizamodels9
 
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabiunwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
Abortion pills in Kuwait Cytotec pills in Kuwait
 
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Anamikakaur10
 
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service NoidaCall Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
dlhescort
 
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
amitlee9823
 
Chandigarh Escorts Service 📞8868886958📞 Just📲 Call Nihal Chandigarh Call Girl...
Chandigarh Escorts Service 📞8868886958📞 Just📲 Call Nihal Chandigarh Call Girl...Chandigarh Escorts Service 📞8868886958📞 Just📲 Call Nihal Chandigarh Call Girl...
Chandigarh Escorts Service 📞8868886958📞 Just📲 Call Nihal Chandigarh Call Girl...
Sheetaleventcompany
 
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
amitlee9823
 

Kürzlich hochgeladen (20)

Falcon Invoice Discounting: The best investment platform in india for investors
Falcon Invoice Discounting: The best investment platform in india for investorsFalcon Invoice Discounting: The best investment platform in india for investors
Falcon Invoice Discounting: The best investment platform in india for investors
 
FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
 
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best ServicesMysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
 
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
 
The Path to Product Excellence: Avoiding Common Pitfalls and Enhancing Commun...
The Path to Product Excellence: Avoiding Common Pitfalls and Enhancing Commun...The Path to Product Excellence: Avoiding Common Pitfalls and Enhancing Commun...
The Path to Product Excellence: Avoiding Common Pitfalls and Enhancing Commun...
 
How to Get Started in Social Media for Art League City
How to Get Started in Social Media for Art League CityHow to Get Started in Social Media for Art League City
How to Get Started in Social Media for Art League City
 
Falcon Invoice Discounting platform in india
Falcon Invoice Discounting platform in indiaFalcon Invoice Discounting platform in india
Falcon Invoice Discounting platform in india
 
Russian Call Girls In Rajiv Chowk Gurgaon ❤️8448577510 ⊹Best Escorts Service ...
Russian Call Girls In Rajiv Chowk Gurgaon ❤️8448577510 ⊹Best Escorts Service ...Russian Call Girls In Rajiv Chowk Gurgaon ❤️8448577510 ⊹Best Escorts Service ...
Russian Call Girls In Rajiv Chowk Gurgaon ❤️8448577510 ⊹Best Escorts Service ...
 
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabiunwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
unwanted pregnancy Kit [+918133066128] Abortion Pills IN Dubai UAE Abudhabi
 
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
Call Now ☎️🔝 9332606886🔝 Call Girls ❤ Service In Bhilwara Female Escorts Serv...
 
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service NoidaCall Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
 
Malegaon Call Girls Service ☎ ️82500–77686 ☎️ Enjoy 24/7 Escort Service
Malegaon Call Girls Service ☎ ️82500–77686 ☎️ Enjoy 24/7 Escort ServiceMalegaon Call Girls Service ☎ ️82500–77686 ☎️ Enjoy 24/7 Escort Service
Malegaon Call Girls Service ☎ ️82500–77686 ☎️ Enjoy 24/7 Escort Service
 
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
Call Girls Electronic City Just Call 👗 7737669865 👗 Top Class Call Girl Servi...
 
Marel Q1 2024 Investor Presentation from May 8, 2024
Marel Q1 2024 Investor Presentation from May 8, 2024Marel Q1 2024 Investor Presentation from May 8, 2024
Marel Q1 2024 Investor Presentation from May 8, 2024
 
Chandigarh Escorts Service 📞8868886958📞 Just📲 Call Nihal Chandigarh Call Girl...
Chandigarh Escorts Service 📞8868886958📞 Just📲 Call Nihal Chandigarh Call Girl...Chandigarh Escorts Service 📞8868886958📞 Just📲 Call Nihal Chandigarh Call Girl...
Chandigarh Escorts Service 📞8868886958📞 Just📲 Call Nihal Chandigarh Call Girl...
 
Falcon's Invoice Discounting: Your Path to Prosperity
Falcon's Invoice Discounting: Your Path to ProsperityFalcon's Invoice Discounting: Your Path to Prosperity
Falcon's Invoice Discounting: Your Path to Prosperity
 
Phases of Negotiation .pptx
 Phases of Negotiation .pptx Phases of Negotiation .pptx
Phases of Negotiation .pptx
 
RSA Conference Exhibitor List 2024 - Exhibitors Data
RSA Conference Exhibitor List 2024 - Exhibitors DataRSA Conference Exhibitor List 2024 - Exhibitors Data
RSA Conference Exhibitor List 2024 - Exhibitors Data
 
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
 
PHX May 2024 Corporate Presentation Final
PHX May 2024 Corporate Presentation FinalPHX May 2024 Corporate Presentation Final
PHX May 2024 Corporate Presentation Final
 

Security: Odoo Code Hardening

  • 1.
  • 4.
  • 7. Security Model Business Data RBAC = Groups + ACL + Rules Apps / Business Logic Access Control
  • 9. A1. Injection A6. Security Misconfiguration A2. Broken Authentication A7. Cross-Site Scripting (XSS) A3. Sensitive Data Exposure A8. Insecure Deserialization A4. XML External Entities (XXE) A9. Vulnerable Components A5. Broken Access Control A10. Insufficient Logging (2017 ed.)
  • 10. HELP? The Odoo framework includes a lot of mechanisms to avoid mistakes. But knowledge and mindset are key!
  • 11. A1. Injection Untrusted data interpreted as code
  • 12. Hello, my name is Robert’); DROP TABLE students;-- 👱 https://xkcd.com/327
  • 13. # SQL Injection (simplified) def _get_partner_match(self, name, partner_type='is_customer'): query = f"""SELECT id FROM res_partner WHERE name ILIKE '%{name}%' AND {partner_type} IS TRUE""" self._cr.execute(query) return self._cr.fetchall()
  • 14. # SQL Injection (simplified) - 2 def _get_partner_match(self, name, partner_type='is_customer'): query = f"""SELECT id FROM res_partner WHERE name ILIKE '%%%(name)s%%' AND {partner_type} IS TRUE """ self._cr.execute(query, (name,)) return self._cr.fetchall()
  • 15. # SQL Injection (simplified) - 3 - Safe! def _get_partner_match(self, name, partner_type='is_customer'): if partner_type not in ('is_customer', 'is_supplier'): raise ValueError() query = f"""SELECT id FROM res_partner WHERE name ILIKE '%%%(name)s%%' AND {partner_type} IS TRUE """ self._cr.execute(query, (name,)) return self._cr.fetchall()
  • 16. # Best option when possible: use the ORM def _get_partner_match(self, name, partner_type='is_customer'): return self.search([('name', 'ilike', name), (partner_type, '=', True)])
  • 17. A2. Broken Auth Authentication / session management logic error
  • 18. A2. Broken Auth Bad news: there are lots of moving parts, it’s hard to get this right. Good news: the system does all of that for you. Be very careful if you try to modify or extend the authentication and session mechanisms. ➔ Securing session cookie ➔ Preventing session injection ➔ Rotating session after login/logout ➔ Storing passwords securely ➔ Verifying passwords securely ➔ Preventing brute-force attacks ➔ Security of password reset flow ➔ Rejecting deactivated users ➔ Instant lockout after account change ➔ Integration with third-party auths ➔ Two-factor flow, token security ➔ ... and much more... What’s so hard?
  • 19.
  • 20. A3. Sensitive Data Exposure Insufficient protection for sensitive data
  • 21. TODO # Sensitive data exposed class Employee(models.Model): _inherit = "hr.employee" ssnid = fields.Char("Social Security Number") passport = fields.Char("Passport No") # Sensitive data protected class Employee(models.Model): _inherit = "hr.employee" ssnid = fields.Char("Social Security Number", groups="hr.group_officer") passport = fields.Char("Passport No", groups="hr.group_officer")
  • 22. A4. XML External Entities Unsafe parsing of untrusted XML data
  • 23. XXE: use safe XML parsers Recursion bombs <!DOCTYPE xmlbomb [ <!ENTITY a "1234567890" > <!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;"> <!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;"> <!ENTITY d "&c;&c;&c;&c;&c;&c;&c;&c;"> ]> <bomb>&d;</bomb> Local File Inclusion <!DOCTYPE external [ <!ENTITY ee SYSTEM "file:///etc/password"> ]> <root>&ee;</root> The framework protects you. Use lxml.etree: etree.fromstring(xml_data) lxml.etree is configured to reject: + recursive entities + network resolution + local entity resolution Or have a look at defusedxml.
  • 24. A5. Broken Access Control Incorrect validation of user permissions
  • 25. # Missing/Incorrect ACLs ➔ The most common mistake! ➔ New models require: + ACLs (CRUD) + Record rules (CRUD filter) + Field-level permission Bad ACLs examples # Full Access to everyone - incorrect id,model_id,group_id,p_read,p_write,p_create,p_unlink access_my_model,model_my_model, ,1,1,1,1 # Full Access to employees - probably incorrect id,model_id,group_id,p_read,p_write,p_create,p_unlink access_my_model,model_my_model,base.group_user,1,1,1,1 Normal ACLs examples # Employee = Read | Manager = Full id,model_id,group_id,p_read,p_write,p_create,p_unlink access_my_model,model_my_model,base.group_user,1,0,0,0 access_my_model,model_my_model,base.group_manager,1,1,1,1 As of V14, also for TransientModel.
  • 26. # Incorrect sudo() or permission test # Portal controller route @route(['/sale/<int:order_id>/approve'], type='json', methods=['POST'], auth='public') def order_approve(self, order_id, **post): order = self.env['sale.order'].sudo().browse(order_id) order.action_approve() user public none converters type methods auth
  • 27. # Incorrect sudo() or permission test # Portal controller route - bad! @route(['/sale/<int:order_id>/approve'], type='json', methods=['POST'], auth='public') def order_approve(self, order_id, **post): order = self.env['sale.order'].sudo().browse(order_id) order.action_approve()
  • 28. # Incorrect sudo() or permission test # Portal controller route - corrected @route(['/sale/<int:order_id>/approve'], type='http', methods=['POST'], auth='public') def order_approve(self, order_id, token, **post): order = self.env['sale.order'].sudo().browse(order_id) if not tools.consteq(order.access_token, token): raise AccessDenied() order.action_approve()
  • 29. # Incorrect sudo() or permission test def get_notifications(self, partner_id): # direct SQL for complex query performance query = """ SELECT DISTINCT m.id, m.author_id, m.message_type FROM mail_message LEFT JOIN mail_message_res_partner_rel LEFT JOIN mail_message_res_partner_needaction_rel needaction (...) WHERE partner_id = %s """ self._cr.execute(query, (partner_id,)) return self._cr.fetchall()
  • 30. # Incorrect sudo() or permission test def _get_notifications(self, partner_id): self.check_access_rights('read') # direct SQL for complex query performance query = """ SELECT DISTINCT m.id, m.author_id, m.message_type FROM mail_message LEFT JOIN mail_message_res_partner_rel LEFT JOIN mail_message_res_partner_needaction_rel needaction (...) WHERE partner_id = %s """ self._cr.execute(query, (partner_id,)) return self._cr.fetchall()
  • 32. odoo.com/documentatio n ● PostgreSQL security (no super user) ● Web server + TLS ● Database manager security ● Separate Production / Staging / Dev ● No demo data on Production ● SSH security ● Rate-limiting and brute-force protections And more... Deployment Checklist
  • 33.
  • 34. A7. XSS Untrusted data interpreted as code… again!
  • 35. Stored / Reflected XSS ➔ Untrusted HTML content in the database, in some text/char field ➔ Victim is tricked into viewing it ➔ When displayed in the browser, it becomes executable @route('/index', type='http', auth="none") def index(self) session_info = { 'user_name': request.env.user.name, } response = request.render( 'web.webclient_bootstrap', {session_info: session_info} ) return response <template id="web.webclient_bootstrap"> <t t-call="web.layout"> <t t-set="head_web"> <script type="text/javascript"> odoo.session_info = <t t-raw="str(session_info)"/>; </script> </t> </t> </template> Name: </script><script>alert(document.cookie);// <script type="text/javascript"> odoo.session_info = {'user_name': "</script><script>alert(document.cookie);//"}; </script>
  • 36. Stored / Reflected XSS ➔ Untrusted HTML content in the database, in some text/char field ➔ Victim is tricked into viewing it ➔ When displayed in the browser, it does not become executable @route('/index', type='http', auth="none") def index(self) session_info = { 'user_name': request.env.user.name, } response = request.render( 'web.webclient_bootstrap', {session_info: session_info} ) return response <template id="web.webclient_bootstrap"> <t t-call="web.layout"> <t t-set="head_web"> <script type="text/javascript"> odoo.session_info = <t t-esc="str(session_info)"/>; </script> </t> </t> </template> Name: </script><script>alert(document.cookie);// <script type="text/javascript"> odoo.session_info = {'user_name': '&lt;/script&gt;&lt;script&gt;alert(document.cookie);//'}; </script>
  • 37. DOM-based XSS Barrier broken between text and markup // Text manipulation elem.textContent = "..."; $elem.text(“..”); // Markup manipulation elem.innerHTML = ""..."; $elem.html(...); Do not mix them. /** * Adds the product description based on attribute values * * @private */ _postProcessContent: function ($modalContent) { var $productDescription = $modalContent .find('.main_product'); var desc = $productDescription.html(); $.each(this.rootProduct.attribute_values, function () { desc += ('<br/>' + this.attribute_value_name + ':' + this.custom_value); }); $productDescription.html(desc); return $modalContent; },
  • 38. DOM XSS Barrier broken between text and markup // Text manipulation elem.textContent = "..."; $elem.text(“..”); // Markup manipulation elem.innerHTML = ""..."; $elem.html(...); Do not mix. Maybe convert. markup = _.escape(text); /** * Adds the product description based on attribute values * * @private */ _postProcessContent: function ($modalContent) { var $productDescription = $modalContent .find('.main_product'); var desc = $productDescription.html(); $.each(this.rootProduct.attribute_values, function () { desc += ('<br/>' + _.escape(this.attribute_value_name) + ':' + _.escape(this.custom_value)); }); $productDescription.html(desc); return $modalContent; },
  • 39. DOM XSS Barrier broken between text and markup // Text manipulation elem.textContent = "..."; $elem.text(“..”); // Markup manipulation elem.innerHTML = ""..."; $elem.html(...); Do not mix. Maybe convert. But, really: do not mix. /** * Adds the product description based on attribute values * * @private */ _postProcessContent: function ($modalContent) { var $productDescription = $modalContent .find('.main_product'); var $customValuesDescription = $('<div>'); $.each(this.rootProduct.attribute_values, function () { $customValuesDescription.append($('<div>', { text: (this.attribute_value_name + ': ' + this.custom_value); })); }); $productDescription.append($customValuesDescription); return $modalContent; },
  • 40. STRING FORMATTING “<b>” + name `<b>${name}</b>` UNSAFE DESERIALIZATION eval() VULNERABLE TEMPLATES t-raw VULNERABLE LIB $.popover() FILES .svg,.html LINKS javascript: XSS VECTORS ARE EVERYWHERE
  • 42. The framework uses safe serialization: ● RPC protocols (JSON-RPC, XML-RPC) ● Cache ● Cookies, sessions ● Signed structured data So watch out: ● Don’t use pickle, use JSON! ● Don’t parse data with eval() ● Sign structured data
  • 45. @classmethod def _login(cls, db, login, password, user_agent_env): ip = request.httprequest.environ['REMOTE_ADDR'] if request else 'n/a' try: # do login ... except AccessDenied: _logger.info("Login failed for db:%s login:%s from %s", db, login, ip) raise _logger.info("Login successful for db:%s login:%s from %s", db, login, ip) _logger.info( "Password reset attempt for <%s> by user <%s> from %s", login, request.env.user.login, request.httprequest.remote_addr) odoo.addons.base.models.res_users: Login failed for db:production login:mike@ex.com from 16.12.19.27 odoo.addons.base.models.res_users: Login successful for db:production login:mike@ex.com from 14.16.23.56 odoo.addons.auth_signup...main: Password reset attempt for <lenny@ex.com> by user <public> from 85.133.187.167
  • 46. def assert_log_admin_access(method): """Decorator checking that the calling user is an administrator, and logging the call. Raise an AccessDenied error if the user does not have administrator privileges """ def check_and_log(method, self, *args, **kwargs): user = self.env.user origin = request.httprequest.remote_addr if request else 'n/a' log_data = (method.__name__, self.sudo().mapped('name'), user.login, user.id, origin) if not self.env.is_admin(): _logger.warning('DENY access to module.%s on %s to user %s ID #%s via %s', *log_data) raise AccessDenied() _logger.info('ALLOW access to module.%s on %s to user %s #%s via %s', *log_data) return method(self, *args, **kwargs) return decorator(check_and_log, method) odoo...ir_module: ALLOW access to module.button_immediate_uninstall on ['crm'] to user bart@ex.com #2 via 2.5.15.214 odoo...ir_module: ALLOW access to module.button_uninstall on ['crm'] to user bart@ex.com #2 via 2.5.15.214 odoo...ir_module: ALLOW access to module.module_uninstall on ['sale_crm', 'crm'] to user __system__ #1 via 2.5.15.214
  • 47. CODE REVIEW CHECKLIST 01 CONTROL ACCESS Groups, ACLs, Rules and Fields 02 VERIFY PERMISSIONS sudo(), controllers, private methods 03 CHECK TEMPLATES t-raw, untrusted input escaped 04 SAFE EVAL Eval only trusted input, iff impossible to avoid BLOCK INJECTIONS 05 Double-check raw SQL, shell commands, etc. XSS PREVENTION 06 DOM, Stored, Reflected, look for the signs!
  • 48. Choose someone who improves the knowledge and mindset of the team.

Hinweis der Redaktion

  1. Could be called “Odoo Security Introduction” ...but strong focus on developers. A talk every year because software security is incredibly important but also very hard.
  2. BUT WHY is that? Is it a difficult engineering challenge, compared to BUILDING a BRIDGE?
  3. STORY: when building a BRIDGE, engineers have a list of the possible PHYSICAL challenges: - earthquake - hurricane - truck spill SOFTWARE: the attacks are creatively invented by the attackers! if something is REMOTELY POSSIBLE - someone will try it - and probably combine different ATTACKS at once! Like having all physical challenges coordinating to attack the bridge --- it would collapse for sure.
  4. The attacker can make all the bad things happen at the same time! How can you counter that? The only way to prevent that is to think like an attacker. But our natural BIAS is different: make things work, consider likely cases // So you need a permanent mindset, and the same knowledge as the attacker
  5. -> MINDSET: THINK like an ATTACKER (Eng bias = make things work, consider likely cases) -> KNOWLEDGE: LEARN about the problems => This talk: best practices for odoo = knowledge => Will have REVIEW CHECKLIST too // But one more thing before we start.. (model) # 00:06
  6. Knowledge: understand the Security Model to be able to defend it. No time to describe it, but you can look at older slides // So where do we start? (risks / OWASP) # 00:09
  7. WHERE TO START: THE FAMOUS OWASP project Comprehensive Directory, Statistics and Tools Community-driven: vendors, users, researchers
  8. MORE TIME ON A5 and A7 because they are the most common problems in Odoo code! We will go over the top 10, see how that applies to Odoo Environments and Apps // … and what can help you fight? (framework!)
  9. ANIM: BUT REMEMBER! KNOWLEDGE + MINDSET No silver bullet can block all problems. // let’s go.. -> A1. Injection # 00:10
  10. Typically in a COMMAND or QUERY sent to an INTERPRETER Very common case, but easy to avoid if you understand data vs code and know the API. // an example: the famous SQLi
  11. The infamous comics from Randall Munroe / XKCD Best known illustration for injection problems!
  12. What do we have here? RAW SQL (perhaps performance, or ignorance) Python 3 f-string `name` = char, `is_customer` = bool Parameters are injected into query PROBLEM: query_type and name are UNTRUSTED DATA -> CODE In reality should use search(), but let’s pretend for a minute we can’t (JOINS, Perf..)
  13. What changed? Name is passed as a query param: good! Notice the double %% escape! But partner_type cannot be a parameter, it’s a column name! Still need to fix partner_type, even if it is a “private method”!
  14. What changed? test for partner_type is useless in general - only prevents attacks! => MINDSET! // and of course the best option… (ORM)
  15. Obvious solution if you can: use search() It works also if the left hand side term is variable. The ORM will take care of: - escaping query parameters - disallow invalid column names # 00:12
  16. There are many moving parts in managing this! Good news: normally it’s all done for you by Odoo.
  17. I can’t go in details over the list on the right, but there’s a lot of things that can go wrong: Managing the session_id is tricky, and it evolves over time (SameSite, Secure, HttpOnly, …) Password management etc. If you ever need to do this: please read the code carefully + OWASP documentation! Each Odoo version comes with auth improvements. // And by the way in v14.. (MFA)
  18. By the way: New in v14: TOTP built-in two-factor authentication Also API Keys No more need for 3rd-party apps or OAuth/LDAP # 00:14
  19. A very common problem: Bad or no encryption (e.g. for password, or personal data) Unnecessary storage (Credit Cards) use PCI third-party
  20. Here is an example with PII (employee personal info) that needs to be protected from other employees! Golden rules: Classify data and protect accordingly (e.g PII - also for GDPR!) What you don’t store cannot be stolen! (PCI Compliance, e.g. acquirers in FORM form - SAQ) # 00:17
  21. An old problem, that can be used for Denial of Service, file disclosure or even remote code execution. Bad or no encryption (e.g. for password, or personal data) Unnecessary storage (Credit Cards)
  22. Famous vulnerability called “Billion Laughs” Odoo implements default protections, but you should be careful with any custom parsing. If you have unusual parsing needs (e.g. SAX), consider defusedxml. # 00:20
  23. One of the 2 MOST COMMON issues we see in reviews! Let’s see some examples of those issues! // This brings us back to the Security Model!
  24. Remember the SECURITY MODEL? This is the CRUX of Odoo SECURITY. For v14: also wizards and transient models!
  25. Another FREQUENT case: Incorrect Direct Object Reference (IDOR) Anatomy of a case for anonymous portal: Converters are run with <auth> permission (so here cannot be sale.order) Auth determines environment permission // Here auth=public (portal) so what permissions? -> (sudo)
  26. Auth=public -> we need to use sudo() to access data! But here we don’t validate who can approve which order? // How can we fix this?
  27. One option = validate it with a token! Other options: auth=user // This is important! Another example?
  28. Now a python method, with RAW SQL. -> Good, no SQL injection right? But SQL bypasses all ACL checks! And it’s PUBLIC and can be called by anyone via RPC! // What should we do?
  29. At least include an explicit ACL check . And make it private! But you may still bypass record rules, so extra precautions may be needed… These are just a few examples.. There are so many more! # 00:30
  30. Examples: Unnecessary features enabled Default parameters left or default credentials Bad deployment security (AWS S3 buckets!)
  31. When you are deploying: be sure to check the Deployment Security guide! // AND BY THE WAY in v14… (Random admin password)
  32. By the way: New in v14: random password generated this first time! # 00:32
  33. One of the 2 MOST COMMON issues we see in reviews! It’s a special form of INJECTION where the execution happens in the browser. Let’s see several cases in details!
  34. Cause: uses `t-raw` with Input untrusted data Why a Problem?: browsers parse <script> tags firsts Solution: escape session_info content (can’t use t-esc) Rule of thumb: always consider data untrusted (don’t try to have “safe variables”) -> suggestion: className instead of adding <b> etc! Impact: Session hijack / steal / MFA bypass / Phishing / ... Here: example with STORED, but reflected is similar. // How can we fix this one? (t-esc)
  35. Fix => use t-esc May not always work, in that case find alternative escaping. // Let’s see another kind of CSS (DOM-based)
  36. TEXT vs MARKUP
  37. ESCAPING text -> markup is an option.
  38. Ideally: do not escape, just don’t mix at all // So we’ve seen 2 examples, but there are so many more… (XSS table)
  39. String formatting or mixing markup and data T-raw vs t-esc (only t-raw with e.g sanitized html field) eval() is not to be used for deserialization! Libraries like bootstrap/jquery contain similar bugs, don’t feed them untrusted data Files and Content-type headers (Odoo defuses them if non admin) JS links inserted in contents (Odoo widgets block it) and more... ADVICE: have someone in the team specialize in this! # 00:42
  40. eval() is not a data parser use JSON Can lead to arbitrary code exec … but not just that! Also security bypass… (think email with token in URL)
  41. Odoo includes safe unpickler, and dropped pickle for protocol and cache. # 00:44
  42. Odoo policy: can’t change lib version in stable, so we review the CVEs Libraries don’t maintain multiple series correctly. Can also be Operating System or even Hardware: SPECTRE/MELTDOWN # 00:46
  43. Very common too, and you find out only when you’re sorry! Also MONITORING
  44. Authentication layer already logs some sensitive operations You should log your own too! // Some built-in tools (assert_log_admin_access decorator)
  45. Log all sensitive actions: payment, login/logout, etc. Also be careful of WHAT you log. // OK, so now that we’ve toured TOP 10 - where do YOU start? (CHECKLIST) # 00:48
  46. List of most important things to check. Keywords / red flags / ... BUT this only the beginning, and it will not be enough...
  47. MOST IMPORTANT! Designate security responsible, ideally 1 per team. Someone who is into security! Who reads and learns! Who does CTF games! # 00:53