Two Scoops of Django
Security Best Practices
Spin Lai
I. Django Configurations
II. Django Security Features
III. Django Admin
IV. What Else ?
I. Django Configurations
II. Django Security Features
III. Django Admin
IV. What Else ?
Django Configurations
Designate Settings
DEBUG / TEMPLATE_DEBUG
ALLOWED_HOSTS
SECRET_KEY
!
Django Configurations
Designate Settings
DEBUG / TEMPLATE_DEBUG
ALLOW_HOSTS
SECRET_KEY
!
$ python manage.py --settings=[set...
Django Configurations
Designate Settings
DEBUG / TEMPLATE_DEBUG
ALLOWED_HOSTS
SECRET_KEY
!
DEBUG = False
!
TEMPLATE_DEBUG =...
Django Configurations
Designate Settings
DEBUG / TEMPLATE_DEBUG
ALLOWED_HOSTS
SECRET_KEY
!
# Must be set when DEBUG = False...
Django Configurations
Designate Settings
DEBUG / TEMPLATE_DEBUG
ALLOWED_HOSTS
SECRET_KEY
!
‣ Configuration values, not code...
Django Configurations
Designate Settings
DEBUG / TEMPLATE_DEBUG
ALLOWED_HOSTS
SECRET_KEY
!
!
def get_env_variable(varname):...
I. Django Configurations
II. Django Security Features
III. Django Admin
IV. What Else ?
Django Security Features
XSS Protection
CSRF Protection
Injection Protection
Clickjacking Protection
SSL / HTTPS
Password ...
Django Security Features
XSS Protection
CSRF Protection
Injection Protection
Clickjacking Protection
SSL / HTTPS
Password ...
Django Security Features
XSS Protection
CSRF Protection
Injection Protection
Clickjacking Protection
SSL / HTTPS
Password ...
CSRF protection
• Django CSRF Protection Workflow
• CSRF Protection for AJAX Request
• HTML Search Form
• CsrfViewMiddlewar...
CSRF protection
• Django CSRF Protection Workflow
• CSRF Protection for AJAX Request
• HTML Search Form
• CsrfViewMiddlewar...
CSRF protection
• Django CSRF Protection Workflow
• CSRF Protection for AJAX Request
• HTML Search Form
• CsrfViewMiddlewar...
CSRF protection
• Django CSRF Protection Workflow
• CSRF Protection for AJAX Request
• HTML Search Form
• CsrfViewMiddlewar...
CSRF protection
• Django CSRF Protection Workflow
• CSRF Protection for AJAX Request
• HTML Search Form
• CsrfViewMiddlewar...
CSRF protection
• Django CSRF Protection Workflow
• CSRF Protection for AJAX Request
• HTML Search Form
• CsrfViewMiddlewar...
CSRF protection
• Django CSRF Protection Workflow
• CSRF Protection for AJAX Request
• HTML Search Form
• CsrfViewMiddlewar...
Django Security Features
XSS Protection
CSRF Protection
Injection Protection
Clickjacking Protection
SSL / HTTPS
Password ...
Injection protection
• Script Injection
• SQL Injection
Injection protection
• Script Injection
• SQL Injection
‣Beware of the eval(), exec() and execfile()
‣DO NOT use `pickle` ...
Injection protection
• Script Injection
• SQL Injection
‣ Django Queryset escape varaibles automatically
‣ Be careful to e...
Django Security Features
XSS Protection
CSRF Protection
Injection Protection
Clickjacking Protection
SSL / HTTPS
Password ...
Clickjacking protection
• `X-Frame-Options` HTTP header
• Configurations
• @xframe_options_exempt
• Browsers Support
Clickjacking protection
• `X-Frame-Options` HTTP header
• Configurations
• @xframe_options_exempt
• Browsers Support
Whethe...
Clickjacking protection
• `X-Frame-Options` HTTP header
• Configurations
• @xframe_options_exempt
• Browsers Support
MIDDLE...
Clickjacking protection
• `X-Frame-Options` HTTP header
• Configurations
• @xframe_options_exempt
• Browsers Support
# Defa...
Clickjacking protection
• `X-Frame-Options` HTTP header
• Configurations
• @xframe_options_exempt
• Browsers Support
Clickjacking protection
• `X-Frame-Options` HTTP header
• Configurations
• @xframe_options_exempt
• Browsers Support
‣ Inte...
Django Security Features
XSS Protection
CSRF Protection
Injection Protection
Clickjacking Protection
SSL / HTTPS
Password ...
SSL / HTTPS
• HTTPS Everywhere !
• Secure Cookies
• HSTS
• Packages
SSL / HTTPS
• HTTPS Everywhere !
• Secure Cookies
• HSTS
• Packages
‣ Web server configuration
‣ Django middleware
‣ SSL c...
SSL / HTTPS
• HTTPS Everywhere !
• Secure Cookies
• HSTS
• Packages
SECURE_PROXY_SSL_HEADER = False
!
$ export HTTPS=on
SSL / HTTPS
• HTTPS Everywhere !
• Secure Cookies
• HSTS
• Packages
SESSION_COOKIE_SECURE = True
!
CSRF_COOKIE_SECURE = Tr...
SSL / HTTPS
• HTTPS Everywhere !
• Secure Cookies
• HSTS
• Packages
‣Redirect HTTP links to HTTPS
‣Web server level config...
SSL / HTTPS
• HTTPS Everywhere !
• Secure Cookies
• HSTS
• Packages
Strict-Transport-Security: max-age=31536000, includeSu...
SSL / HTTPS
• HTTPS Everywhere !
• Secure Cookies
• HSTS
• Packages
‣ django-sslify
‣ django-secure
‣ django-hstsmiddleware
Django Security Features
XSS Protection
CSRF Protection
Injection Protection
Clickjacking Protection
SSL / HTTPS
Password ...
Password Storage
• PBKDF2 + SHA256
• User.password
• PASSWORD_HASHER
• Use bcrypt
• Increase work factor
Password Storage
• PBKDF2 + SHA256
• User.password
• PASSWORD_HASHER
• Use bcrypt
• Increase work factor
Password Storage
• PBKDF2 + SHA256
• User.password
• PASSWORD_HASHER
• Use bcrypt
• Increase work factor
<algorithm>$<iter...
Password Storage
• PBKDF2 + SHA256
• User.password
• PASSWORD_HASHER
• Use bcrypt
• Increase work factor
PASSWORD_HASHERS ...
Password Storage
• PBKDF2 + SHA256
• User.password
• PASSWORD_HASHER
• bcrypt
• Increase work factor
Password Storage
• PBKDF2 + SHA256
• User.password
• PASSWORD_HASHER
• Use bcrypt
• Increase work factor
Django Security Features
XSS Protection
CSRF Protection
Injection Protection
Clickjacking Protection
SSL / HTTPS
Password ...
Data Validation
• Django Forms
• User-Uploaded Content
Data Validation
• Django Forms
• User-Uploaded Content
‣ Designed to validate Python dictionaries
‣ Not only for HTTP POST...
Data Validation
• Django Forms
• User-Uploaded Content
from django import forms
from .models import Store
!
class StoreFor...
Data Validation
• Django Forms
• User-Uploaded Content
from django import forms
from .models import Store
!
class StoreFor...
Data Validation
• Django Forms
• User-Uploaded Content
‣ Limit upload in web server
‣ FileField / ImageField
‣ python-magi...
Data Validation
• Django Forms
• User-Uploaded Content
from django.utils.image import Image
!
try:
Image.open(file).verify...
I. Django Configurations
II. Django Security Features
III. Django Admin
IV. What Else ?
Django Admin
Change the Default Admin URL
Access Admin via HTTPS
Limited Access Based on IP
Use `allow_tags` attribute wit...
Django Admin
Change the Default Admin URL
Access Admin via HTTPS
Limited Access Based on IP
Use `allow_tags` attribute wit...
Django Admin
Change the Default Admin URL
Access Admin via HTTPS
Limited Access Based on IP
Use `allow_tags` attribute wit...
Django Admin
Change the Default Admin URL
Access Admin via HTTPS
Limited Access Based on IP
Use `allow_tags` attribute wit...
Django Admin
Change the Default Admin URL
Access Admin via HTTPS
Limited Access Based on IP
Use `allow_tags` attribute wit...
Django Admin
Change the Default Admin URL
Access Admin via HTTPS
Limited Access Based on IP
Use `allow_tags` attribute wit...
Django Admin
Change the Default Admin URL
Access Admin via HTTPS
Limited Access Based on IP
Use `allow_tags` attribute wit...
I. Django Configurations
II. Django Security Features
III. Django Admin
IV. What Else ?
What else ?
Harden your servers
NEVER store credit card data
Server monitoring
Vulnerability reporting page
Keep things up...
What else ?
Harden your servers
NEVER store credit card data
Server monitoring
Vulnerability reporting page
Keep things up...
What else ?
Harden your servers
NEVER store credit card data
Server monitoring
Vulnerability reporting page
Keep things up...
What else ?
Harden your servers
NEVER store credit card data
Server monitoring
Vulnerability reporting page
Keep things up...
What else ?
Harden your servers
NEVER store credit card data
Server monitoring
Vulnerability reporting page
Keep things up...
What else ?
Harden your servers
NEVER store credit card data
Server monitoring
Vulnerability reporting page
Keep things up...
What else ?
Harden your servers
NEVER store credit card data
Server monitoring
Vulnerability reporting page
Keep things up...
What else ?
Harden your servers
NEVER store credit card data
Server monitoring
Vulnerability reporting page
Keep things up...
What else ?
Harden your servers
NEVER store credit card data
Server monitoring
Vulnerability reporting page
Keep things up...
Keep Things Up-to-Date
• Dependencies
• Security Practices
Keep Things Up-to-Date
• Dependencies
• Security Practiceshttps://www.djangoproject.com/weblog/
Keep Things Up-to-Date
• Dependencies
• Security Practices
Keep Things Up-to-Date
• Dependencies
• Security Practices
Keep Things Up-to-Date
• Dependencies
• Security Practices
Thank You
Two scoops of Django - Security Best Practices
Upcoming SlideShare
Loading in...5
×

Two scoops of Django - Security Best Practices

2,223

Published on

The presentation is based on the book 「Two scoops of Django : Best Practices for Django 1.5」by Daniel Greenfeld and Audrey Roy.

Published in: Software, Technology, Business
2 Comments
9 Likes
Statistics
Notes
No Downloads
Views
Total Views
2,223
On Slideshare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
53
Comments
2
Likes
9
Embeds 0
No embeds

No notes for slide

Two scoops of Django - Security Best Practices

  1. 1. Two Scoops of Django Security Best Practices Spin Lai
  2. 2. I. Django Configurations II. Django Security Features III. Django Admin IV. What Else ?
  3. 3. I. Django Configurations II. Django Security Features III. Django Admin IV. What Else ?
  4. 4. Django Configurations Designate Settings DEBUG / TEMPLATE_DEBUG ALLOWED_HOSTS SECRET_KEY !
  5. 5. Django Configurations Designate Settings DEBUG / TEMPLATE_DEBUG ALLOW_HOSTS SECRET_KEY ! $ python manage.py --settings=[setting path] $ django-admin.py --settings=[setting path] $ export DJANGO_SETTINGS_MODULE=[setting path]
  6. 6. Django Configurations Designate Settings DEBUG / TEMPLATE_DEBUG ALLOWED_HOSTS SECRET_KEY ! DEBUG = False ! TEMPLATE_DEBUG = False
  7. 7. Django Configurations Designate Settings DEBUG / TEMPLATE_DEBUG ALLOWED_HOSTS SECRET_KEY ! # Must be set when DEBUG = False ALLOWED_HOSTS = [ 'localhost', 'www.example.com', '.example.com', '*' # Avoid ! ]
  8. 8. Django Configurations Designate Settings DEBUG / TEMPLATE_DEBUG ALLOWED_HOSTS SECRET_KEY ! ‣ Configuration values, not code. ‣ DO NOT keep them in version control. ‣ Use environment variables.
  9. 9. Django Configurations Designate Settings DEBUG / TEMPLATE_DEBUG ALLOWED_HOSTS SECRET_KEY ! ! def get_env_variable(varname): try: return os.environ[varname] except KeyError: msg = "Set the %s environment variable" % var_name raise ImporperlyConfigured(msg)
  10. 10. I. Django Configurations II. Django Security Features III. Django Admin IV. What Else ?
  11. 11. Django Security Features XSS Protection CSRF Protection Injection Protection Clickjacking Protection SSL / HTTPS Password Storage Data Validation
  12. 12. Django Security Features XSS Protection CSRF Protection Injection Protection Clickjacking Protection SSL / HTTPS Password Storage Data Validation ‣ Django by default escapes specific characters ‣ Be careful when using is_safe attribute ‣ Be very careful when storing HTML in Database
  13. 13. Django Security Features XSS Protection CSRF Protection Injection Protection Clickjacking Protection SSL / HTTPS Password Storage Data Validation
  14. 14. CSRF protection • Django CSRF Protection Workflow • CSRF Protection for AJAX Request • HTML Search Form • CsrfViewMiddleware rather than @csrf_protect • Be careful with @csrf_exempt
  15. 15. CSRF protection • Django CSRF Protection Workflow • CSRF Protection for AJAX Request • HTML Search Form • CsrfViewMiddleware rather than csrf_protect() • Be careful with csrf_exempt() ‣ Random token value by CsrfViewMiddleware (CSRF cookie) ‣ `csrf_token` template tag generate hidden input ‣ Every request calls django.middleware.csrf.get_token() ‣ Compare CSRF cookie with `csrfmiddlewaretoken` value ‣ With HTTPS, CsrfViewMiddleWare will check referer header
  16. 16. CSRF protection • Django CSRF Protection Workflow • CSRF Protection for AJAX Request • HTML Search Form • CsrfViewMiddleware rather than csrf_protect() • Be careful with csrf_exempt() ‣ Pass CSRF token as POST data with every POST request ‣ Set a custom `X-CSRFToken` header on each request ‣ CSRF cookie might not exist without `csrf_token` tag
  17. 17. CSRF protection • Django CSRF Protection Workflow • CSRF Protection for AJAX Request • HTML Search Form • CsrfViewMiddleware rather than csrf_protect() • Be careful with csrf_exempt() var origSync = Backbone.sync; Backbone.sync = function (method, model, options) { options.beforeSend = function (xhr) { xhr.setRequestHeader('X-CSRFToken', $.cookie('csrftoken')); }; ! return origSync(method, model, options); };
  18. 18. CSRF protection • Django CSRF Protection Workflow • CSRF Protection for AJAX Request • HTML Search Form • CsrfViewMiddleware rather than @csrf_protect • Be careful with @csrf_exempt
  19. 19. CSRF protection • Django CSRF Protection Workflow • CSRF Protection for AJAX Request • HTML Search Form • CsrfViewMiddleware rather than @csrf_protect • Be careful with @csrf_exempt
  20. 20. CSRF protection • Django CSRF Protection Workflow • CSRF Protection for AJAX Request • HTML Search Form • CsrfViewMiddleware rather than @csrf_protect • Be careful with @csrf_exempt
  21. 21. Django Security Features XSS Protection CSRF Protection Injection Protection Clickjacking Protection SSL / HTTPS Password Storage Data Validation
  22. 22. Injection protection • Script Injection • SQL Injection
  23. 23. Injection protection • Script Injection • SQL Injection ‣Beware of the eval(), exec() and execfile() ‣DO NOT use `pickle` module to serialize/deserialize data. ‣Only use safe_load() in PyYAML
  24. 24. Injection protection • Script Injection • SQL Injection ‣ Django Queryset escape varaibles automatically ‣ Be careful to escape raw SQL properly ‣ Exercise caution when using extra()
  25. 25. Django Security Features XSS Protection CSRF Protection Injection Protection Clickjacking Protection SSL / HTTPS Password Storage Data Validation
  26. 26. Clickjacking protection • `X-Frame-Options` HTTP header • Configurations • @xframe_options_exempt • Browsers Support
  27. 27. Clickjacking protection • `X-Frame-Options` HTTP header • Configurations • @xframe_options_exempt • Browsers Support Whether or not a resource is allowed to load within a frame or iframe
  28. 28. Clickjacking protection • `X-Frame-Options` HTTP header • Configurations • @xframe_options_exempt • Browsers Support MIDDLEWARE_CLASSES = ( ... 'django.middleware.clickjacking.XFrameOptionsMiddleware', ... )
  29. 29. Clickjacking protection • `X-Frame-Options` HTTP header • Configurations • @xframe_options_exempt • Browsers Support # Default X_FRAME_OPTIONS = 'SAMEORIGIN' ! X_FRAME_OPTIONS = 'DENY'
  30. 30. Clickjacking protection • `X-Frame-Options` HTTP header • Configurations • @xframe_options_exempt • Browsers Support
  31. 31. Clickjacking protection • `X-Frame-Options` HTTP header • Configurations • @xframe_options_exempt • Browsers Support ‣ Internet Explorer 8+ ‣ Firefox 3.6.9+ ‣ Opera 10.5+ ‣ Safari 4+ ‣ Chrome 4.1+
  32. 32. Django Security Features XSS Protection CSRF Protection Injection Protection Clickjacking Protection SSL / HTTPS Password Storage Data Validation
  33. 33. SSL / HTTPS • HTTPS Everywhere ! • Secure Cookies • HSTS • Packages
  34. 34. SSL / HTTPS • HTTPS Everywhere ! • Secure Cookies • HSTS • Packages ‣ Web server configuration ‣ Django middleware ‣ SSL certificate from reputable source
  35. 35. SSL / HTTPS • HTTPS Everywhere ! • Secure Cookies • HSTS • Packages SECURE_PROXY_SSL_HEADER = False ! $ export HTTPS=on
  36. 36. SSL / HTTPS • HTTPS Everywhere ! • Secure Cookies • HSTS • Packages SESSION_COOKIE_SECURE = True ! CSRF_COOKIE_SECURE = True
  37. 37. SSL / HTTPS • HTTPS Everywhere ! • Secure Cookies • HSTS • Packages ‣Redirect HTTP links to HTTPS ‣Web server level configuration ‣HSTS-compliant browsers
  38. 38. SSL / HTTPS • HTTPS Everywhere ! • Secure Cookies • HSTS • Packages Strict-Transport-Security: max-age=31536000, includeSubDomains
  39. 39. SSL / HTTPS • HTTPS Everywhere ! • Secure Cookies • HSTS • Packages ‣ django-sslify ‣ django-secure ‣ django-hstsmiddleware
  40. 40. Django Security Features XSS Protection CSRF Protection Injection Protection Clickjacking Protection SSL / HTTPS Password Storage Data Validation
  41. 41. Password Storage • PBKDF2 + SHA256 • User.password • PASSWORD_HASHER • Use bcrypt • Increase work factor
  42. 42. Password Storage • PBKDF2 + SHA256 • User.password • PASSWORD_HASHER • Use bcrypt • Increase work factor
  43. 43. Password Storage • PBKDF2 + SHA256 • User.password • PASSWORD_HASHER • Use bcrypt • Increase work factor <algorithm>$<iteration>$<salt>$<hash>
  44. 44. Password Storage • PBKDF2 + SHA256 • User.password • PASSWORD_HASHER • Use bcrypt • Increase work factor PASSWORD_HASHERS = ( 'django.contrib.auth.hashers.PBKDF2PasswordHasher', 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher', 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher', 'django.contrib.auth.hashers.BCryptPasswordHasher', 'django.contrib.auth.hashers.SHA1PasswordHasher', 'django.contrib.auth.hashers.MD5PasswordHasher', 'django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher', 'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher', 'django.contrib.auth.hashers.CryptPasswordHasher', )
  45. 45. Password Storage • PBKDF2 + SHA256 • User.password • PASSWORD_HASHER • bcrypt • Increase work factor
  46. 46. Password Storage • PBKDF2 + SHA256 • User.password • PASSWORD_HASHER • Use bcrypt • Increase work factor
  47. 47. Django Security Features XSS Protection CSRF Protection Injection Protection Clickjacking Protection SSL / HTTPS Password Storage Data Validation
  48. 48. Data Validation • Django Forms • User-Uploaded Content
  49. 49. Data Validation • Django Forms • User-Uploaded Content ‣ Designed to validate Python dictionaries ‣ Not only for HTTP POST request ‣ DO NOT use ModelForms.Meta.exclude ‣ Use ModelForms.Meta.fields instead
  50. 50. Data Validation • Django Forms • User-Uploaded Content from django import forms from .models import Store ! class StoreForm(forms.ModelForm): ! class Meta: model = Store # Don't Do this!! excludes = ("pk", "slug", "modified")
  51. 51. Data Validation • Django Forms • User-Uploaded Content from django import forms from .models import Store ! class StoreForm(forms.ModelForm): ! class Meta: model = Store # Explicitly specifying what we want fields = ("title", "address", "email")
  52. 52. Data Validation • Django Forms • User-Uploaded Content ‣ Limit upload in web server ‣ FileField / ImageField ‣ python-magic ‣ Validate with specific file type library
  53. 53. Data Validation • Django Forms • User-Uploaded Content from django.utils.image import Image ! try: Image.open(file).verify() except Exception: # Pillow (or PIL) doesn't recognize it as an image. six.reraise(ValidationError, ValidationError( self.error_messages['invalid_image'], code='invalid_image', ), sys.exc_info()[2])
  54. 54. I. Django Configurations II. Django Security Features III. Django Admin IV. What Else ?
  55. 55. Django Admin Change the Default Admin URL Access Admin via HTTPS Limited Access Based on IP Use `allow_tags` attribute with Caution Admin Docs Packages
  56. 56. Django Admin Change the Default Admin URL Access Admin via HTTPS Limited Access Based on IP Use `allow_tags` attribute with Caution Admin Docs Packages
  57. 57. Django Admin Change the Default Admin URL Access Admin via HTTPS Limited Access Based on IP Use `allow_tags` attribute with Caution Admin Docs Packages
  58. 58. Django Admin Change the Default Admin URL Access Admin via HTTPS Limited Access Based on IP Use `allow_tags` attribute with Caution Admin Docs Packages ‣ Web server configuration ‣ Django middleware
  59. 59. Django Admin Change the Default Admin URL Access Admin via HTTPS Limited Access Based on IP Use `allow_tags` attribute with Caution Admin Docs Packages
  60. 60. Django Admin Change the Default Admin URL Access Admin via HTTPS Limited Access Based on IP Use `allow_tags` attribute with Caution Admin Docs Packages
  61. 61. Django Admin Change the Default Admin URL Access Admin via HTTPS Limited Access Based on IP Use `allow_tags` attribute with Caution Admin Docs Packages ‣ django-admin-honeypot ‣ django-axes
  62. 62. I. Django Configurations II. Django Security Features III. Django Admin IV. What Else ?
  63. 63. What else ? Harden your servers NEVER store credit card data Server monitoring Vulnerability reporting page Keep things up-to-date
  64. 64. What else ? Harden your servers NEVER store credit card data Server monitoring Vulnerability reporting page Keep things up-to-date
  65. 65. What else ? Harden your servers NEVER store credit card data Server monitoring Vulnerability reporting page Keep things up-to-date ‣ PCI-DSS Security Standards ‣ Sufficient Time/Resource/Funds ‣ Using 3rd-Party Services ‣ Beware of Open Source Solutions
  66. 66. What else ? Harden your servers NEVER store credit card data Server monitoring Vulnerability reporting page Keep things up-to-date ‣ Check access/error logs regularly ‣ Install monitoring tools
  67. 67. What else ? Harden your servers NEVER store credit card data Server monitoring Vulnerability reporting page Keep things up-to-date
  68. 68. What else ? Harden your servers NEVER store credit card data Server monitoring Vulnerability reporting page Keep things up-to-date
  69. 69. What else ? Harden your servers NEVER store credit card data Server monitoring Vulnerability reporting page Keep things up-to-date
  70. 70. What else ? Harden your servers NEVER store credit card data Server monitoring Vulnerability reporting page Keep things up-to-date
  71. 71. What else ? Harden your servers NEVER store credit card data Server monitoring Vulnerability reporting page Keep things up-to-date
  72. 72. Keep Things Up-to-Date • Dependencies • Security Practices
  73. 73. Keep Things Up-to-Date • Dependencies • Security Practiceshttps://www.djangoproject.com/weblog/
  74. 74. Keep Things Up-to-Date • Dependencies • Security Practices
  75. 75. Keep Things Up-to-Date • Dependencies • Security Practices
  76. 76. Keep Things Up-to-Date • Dependencies • Security Practices
  77. 77. Thank You
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×