- Access Protection With Authorization Checks
- Best Practices
- Data Storage
- User Interface
- Attack Vectors
- Getting Help
These security guidelines are for both core and application developers. They:
highlight some of the most common security problems and how to prevent them.
give you some best practices and tips about security when developing with ownCloud.
Please use them to assess how secure your application is.
Program defensively: for instance always check for CSRF or escape strings, even if you do not need it. Doing so prevents future problems where you might miss a change that leads to a security hole.
All application Framework security features depend on the call of the
OCA\\AppFramework\\App::main. If the controller
method executes directly, security checks are not performed!
Source Code Analysis
Before releasing an application and after security-related changes, the complete source code must be scanned. We currently use RIPS to perform scans. Affected Software:
All apps in core
All apps in the marketplace
Security Related Comments in Source Code
Usernames and passwords
Descriptions of processes and algorithms
HTTP or HTTPS
Only use HTTPS for rendering content.
Avoid switching between HTTP and HTTPS, which creates mixed-content pages.
Security Related Actions
All security-related actions must take place on the server. This includes validation, authentication, and authorization. Authorization implementations on the client side are only useful for providing a better user experience.
Don’t hard-code passwords or encryption keys in the source code. They have to be in config files and should be user-generated.
Least Privilege Principle
Every application should only have the rights that it needs.
An application should not access core database tables. If it needs data from these tables, it should call an API endpoint to retrieve it.
Error Messages and Error Pages
Don’t show sensitive information on error pages or in error messages. Sensitive information includes:
Don’t show overly detailed information in error messages or on error pages.
If a user can’t login, don’t show an error like:
Your password is wrong. Instead, show a message such as:
There was an error with your credentials. If you print
Your password is wrongthen an attacker knows the username was a valid one in the ownCloud installation.
Consider implementing a CAPTCHA to prevent brute force attacks, after five failed login attempts.
Session ID Transport
New Session ID After a Successful Login
After a successful login, regenerate the session id to prevent session fixation attacks.
If you have to switch between HTTPS and HTTP, you should change the session id, because an attacker could have already read the session id.
Access Protection With Authorization Checks
Every request to the server must check if the user has the authorization to perform this request. We do not recommend running these on the client-side, as they can be avoided. However, client-side checks can improve the user’s experience.
Use of the eval Function
evalfunctions — especially not with user-supplied data.
All user-supplied data,
$_COOKIEvariables must be validated. All these contain data which can be changed (or forged) by the client.
Sanitize any supplied script code.
If you expect to receive an integer id as a GET parameter, then always
explicitly cast it into an integer using the cast operator
$_REQUEST parameters are strings. However, if you expect
text as a parameter, use
PHP’s htmlspecialchars function with
strip_tags to prevent Cross-site Scripting (XSS) attacks.
<?php $neu = htmlspecialchars("<a href='test'>Test</a>", ENT_QUOTES); echo $neu; // <a href='test'>Test</a>
<?php $text = '<p>Test-Absatz.</p><!-- Kommentar --> <a href="#fragment">Anderer Text</a>'; echo strip_tags($text); echo "\n";
Test-Absatz. Anderer Text <p>Test-Absatz.</p> <a href="#fragment">Anderer Text</a>
Do the validation before all other actions.
Path Traversal and Path Manipulation
Don’t use user-supplied data to build path names, if you need to access the file system. You have to check the input parameters for null bytes (
\0), the links to the current and parent directory on UNIX/Linux filesystems (
..), and empty strings.
Prevent Command Injection
Use PHP’s escapeshellarg() function, if your input parameters are arguments for exec(), popen(), system(), or the backtick (``) operator.
<?php system('ls '.escapeshellarg($dir));
If you do not know how many arguments your application receives, then use the PHP function escapeshellcmd() to escape the whole command.
<?php $command = './configure '.$_POST['configure_options']; $escaped_command = escapeshellcmd($command); system($escaped_command);
All input parameters printed out in the response should be escaped.
Do not use
print_unescaped()in ownCloud templates, use
$jQuery.html(), if you want to output HTML, . A better option is to use a tool like HTMLPurifier.
High Sensitive Information in GET Request
You should not use sensitive information, like passwords or usernames, in unprotected requests.
All requests containing sensitive information should be protected with HTTPS.
Prevent HTTP-Header-Injection (HTTP Response Splitting)
To prevent HTTP Response Splitting, check all request variables for
%0a(LF), if they are parameters provided to PHP’s header() function. This is because an attacker can deface your website, such as redirect the request to a phishing site or executing an XSS attack, by performing header manipulation.
Changes on the Document Object Model (DOM)
Don’t use unvalidated user input, if your code changes the DOM.
You should never trust user input.
Use the escape functions for your database to prevent SQL Injection attacks, if you have to pass parameters to a SQL query. In ownCloud you must use the QueryBuilder.
Persistent Storages on Client Side
Don’t save highly sensitive data in persistent storage on the client side. Persistent data storage includes:
Release all Resources in Case of an Error
All resources, such as database and file locks, must be released when errors occur. Doing so prevents the server from being subject to denial-of-service (DOS) attacks.
Symmetric Encryption Methods
If you use symmetric encryption methods in your code, use the following encryption types:
AES with a key length of 256
SERPENT with a key length of 256
For block ciphers use the following modes:
CFB (cipher feedback mode)
CBC (cipher block chaining mode)
CFB mode requires an initialization vector (IV) to the respective cipher function. Whereas in CBC mode, supplying one is optional. The IV must be unique and must be the same when encrypting and decrypting. Use the PHP crypt library with libmcrypt greater 2.4.x.
Asymmetric Encryption Methods
If you use asymmetric encryption methods, use RSA encryption with a key length of 4096.
If you need a hash function in PHP, use the SHA512 hash algorithm.
You can use PHP’s crypt() function, but only with a strong salt.
Don’t use MD5, SHA1 or SHA256. These types of algorithms are designed to be very fast and efficient. However, with modern techniques and computer equipment, it has become trivial to brute force the output of these algorithms to discover the original input.
If you use HTTPS to protect requests, then use the secure flag for your cookies.
The following chapter is not only for developers but also for admins and end-users.
Charset of Passwords
The charset of a password should contain characters, numbers, and special characters.
Characters should be both upper and lowercase.
All passwords should have a minimum length of eight characters and contain numbers and special characters. These requirements must be validated by the application.
If the user can choose his password for the first time, the quality of a password should be displayed graphically.
If a user can input his password into an input field, the input field must be of type
If an error occurs, don’t fill the password field automatically when displaying an error message.
Don’t save passwords in clear text. Use a salted hash
Auto-complete must be disabled for all input fields which receive sensitive data. Sensitive data includes:
Credit card information
For text input fields use
autocomplete="off"or use a dynamically generated field name.
For password fields use:
<input name="pass" type="password" autocomplete="new-password" />
Auth bypass / Privilege escalations
Auth bypass/privilege escalations happen when users can perform unauthorized actions. ownCloud offers three simple checks:
OCP\JSON::checkLoggedIn(): Checks if the logged in user is logged in
OCP\JSON::checkAdminUser(): Checks if the logged in user has admin privileges
OCP\JSON::checkSubAdminUser(): Checks if the logged in user has group admin privileges
These checks are already automatically performed, by the application framework, for each request. If they are not required, they have to be explicitly turned off by using annotations above your controller method. Additionally, always check /if the user has the right to perform that action.
Clickjacking tricks the user to click into an invisible iframe to perform an arbitrary action (e.g., deleting a user account).
To prevent such attacks ownCloud sends the X-Frame-Options header to all template responses. Don’t remove this header unless you need to!
This functionality is built into ownCloud when ownCloud templates or Twig Templates are used.
Code executions / File inclusions
Code execution means that an attacker can include an arbitrary PHP file. This PHP file runs with all the privileges granted to the normal application and can do an enormous amount of damage. Code executions and file inclusions can be easily prevented by never allowing user-input to run through the following functions:
Never allow the user to upload files into a folder which is reachable from the URL!
<?php require("/includes/" . $_GET['file']);
If you have to pass user input to a potentially dangerous function, double check to be sure that there is no other option available. If there is no other option, sanitize every user parameter and ask people to audit your sanitize functions.
Cross Site Request Forgery (CSRF)
Using CSRF one can trick a user into executing a request that he did not want to make. Thus every POST and GET request needs to be protected against it. The only places where no CSRF checks are needed are in the main template, which is rendering the application, or in externally callable interfaces.
Submitting a form is also a POST/GET request!
To prevent CSRF in an app, be sure to call the following method at the top of all your files:
If you are using the application Framework, every controller method is automatically checked for CSRF unless you explicitly exclude it by setting the
@NoCSRFRequired annotation before the controller method.
Cross Site Scripting (XSS)
Let’s assume you use the following example in your application:
<?php echo $_GET['username'];
An attacker might now easily send the user a link to
app.php?username=<script src="attacker.tld"></script>, to take control
of the user account. The same problem occurs when outputting content
from the database, or any other location that is writable by users.
Another attack vector that is often overlooked is XSS vulnerabilities in
attributes like this:
To prevent XSS in your app, never use
p() instead. Doing so sanitizes input. Also validate URLs to start
with the expected protocol (starts with
http for instance)!
Should you ever need to print something unescaped, double check if it is necessary. If there is no other way (e.g., when including sub-templates) use print_unescaped with care.
var html = '<li>' + username + '</li>"';
var html = '<li>' + escapeHTML(username) + '</li>';
An even better way to make your application safer is to use the jQuery built-in function $.text(), instead of $.html().
Very often, developers forget about sanitizing the file path (such as
/). Doing so allows an attacker to traverse
through directories on the server and opens several potential attack
vendors, which include privilege escalations, code executions, and
<?php $username = OC_User::getUser(); fopen("/data/" . $username . "/" . $_GET['file'] . ".txt");
<?php $username = OC_User::getUser(); $file = str_replace(array('/', '\\'), `, $_GET['file']); fopen("/data/" . $username . "/" . $file . ".txt");
PHP also interprets the backslash (\) in paths, don’t forget to replace it too!
Shell Injection occurs if PHP code executes shell commands (e.g., running a latex compiler). Before doing this, check if there is a PHP library that already provides the needed functionality. If you really need to execute a command be aware that you have to escape every user parameter passed to one of these functions:
Please require/request additional programmers to audit your escape function.
Without escaping the user input, this allows an attacker to execute arbitrary shell commands on your server. PHP offers the following functions to escape user input:
escapeshellarg(): Escape a string to be used as a shell argument
escapeshellcmd(): Escape shell metacharacters
<?php system('ls '.$_GET['dir']);
<?php system('ls '.escapeshellarg($_GET['dir']));
Sensitive data exposure
Always store user data or configuration files in safe locations, e.g., owncloud/data/ and not in the web root, where they are accessible by anyone using a web browser.
SQL Injection occurs when SQL query strings are concatenated with variables. To prevent this, always use prepared queries:
<?php $sql = 'SELECT * FROM `users` WHERE `id` = ?'; $query = \OCP\DB::prepare($sql); $params = array(1); $result = $query->execute($params);
If the application Framework is used, write SQL queries like this in the class that extends the Mapper:
<?php // inside a child mapper class $sql = 'SELECT * FROM `users` WHERE `id` = ?'; $params = array(1); $result = $this->execute($sql, $params);
This is more of an annoyance than a critical security vulnerability since it may be used for social engineering or phishing. Before redirecting, always validate the URL if the requested URL is on the same domain or is an allowed resource.
<?php header('Location:'. $_GET['redirectURL']);
<?php header('Location: https://example.com'. $_GET['redirectURL']);
If you need help to ensure that a function is secure, please ask on our chat system for details.