Skip to main content

A guide to programming safe JavaScript plugins for Safari users

Unsafe JS plugins

In recent years, actually over a decade now, there have been instances of very unsafe JS plugins causing big issues for Safari users.

They exploit vulnerabilities in the browser or even in one's macOS, and lead to various types of havoc, including data breaches, performance degradation, security risks, and so on.

For the curious, here are a few notable relatively recent examples:

1. Malicious adware plugins

Some JavaScript plugins, disguised as helpful tools or enhancements, have been found to contain adware.

These plugins can inject unwanted advertisements into webpages, redirect users to malicious sites, or even track their browsing habits without consent. Not a biggie. But a notable case involved adware plugins that redirected users to phishing sites or installed additional malicious software on their devices...

2. Cryptojacking plugins

Those stand for the unauthorized use of someone’s computer to mine cryptocurrency. Those are the ones that have cryptojacking scripts that hijack Safari's resources to mine cryptocurrencies like Bitcoin or Monero. This was really happening and not only slowed down the user's device but also significantly increased power consumption, potentially damaging hardware over time. Expensive hardware.

3. Exploitation of browser vulnerabilities

Some plugins have been designed to exploit specific vulnerabilities in Safari. There have been cases where plugins exploited zero-day vulnerabilities, allowing attackers to execute arbitrary code on the user's machine. This can lead to a complete system compromise, giving attackers access to sensitive data and even the ability to fully control the infected device remotely.

4. Data harvesting plugins

They harvest personal data without user consent. These plugins can collect browsing history, personal information, and even our login credentials. This data is often sold to third parties or used in targeted phishing attacks. An example of this was a plugin that posed as a social media enhancement tool but instead collected users' social media credentials.

5. Browser hijacking plugins

These 'hijack' the user's browser, altering the search results, changing the default search engine, or modifying the homepage.

These plugins often make it difficult for the users to revert these changes and can expose them to additional security risks by redirecting them to malicious sites.

Not the worst one but worth mentioning.

Two most notable incidents

- Back in 2018: The 2018 Coinhive Incident - Coinhive, a popular JavaScript-based cryptocurrency miner, was found embedded in several websites without users' knowledge. It was exploiting the browser to mine Monero, and has caused significant performance issues for a large number of Safari users.

- Back in 2019: The 2019 Facebook SDK Vulnerability - A vulnerability in the Facebook SDK for JavaScript affected several websites, allowing attackers to take over user sessions and gain unauthorized access to accounts.

Now, we're interested in doing our codes ethically. In that case, creating safe and secure JavaScript plugins for Safari involves more than just understanding basic principles. Let's be more specific:

Get to know Safari extensions basics

There's a specific architecture to it.

Safari app extensions: These extensions are part of a macOS app and use native APIs to interact with Safari. Learn about Safari app extensions.

Web extensions: These are based on the W3C Browser Extensions standard and can be used across different browsers, including Safari. Refer to the Safari web extensions documentation.

Both Safari App Extensions and Web Extensions can utilize JavaScript for scripting purposes, including the use of the JavaScript Date object for handling date and time operations. This standard object is crucial for various functionalities like scheduling tasks, logging events, and manipulating date and time data within the extensions.

While there is usually nothing inherently wrong with using the JavaScript Date object for legitimate purposes, it has been, and can be, misused by malicious actors within Safari extensions to perform harmful activities. Here are some examples:

- Denial of Service (DoS) attack: An attacker can create an infinite loop of heavy date calculations, causing the browser to become unresponsive or crash

// Malicious code in a Safari plugin

function causeHighCPUUsage() {

    while (true) {

        let start = new Date();

        for (let i = 0; i < 1e7; i++) {

            let tempDate = new Date(start.getTime() + i * 1000);

        }

    }

}

causeHighCPUUsage();

 

- Cross-site scripting (XSS): If a plugin improperly handles date input from users, it could be exploited to inject malicious scripts.

// Malicious date handling in a Safari plugin

safari.extension.addContentScript(`

    document.getElementById('dateInput').addEventListener('change', function() {

        let userInput = this.value;

        // Vulnerable to XSS if not properly sanitized

        document.getElementById('output').innerHTML = new Date(userInput);

    });

`);

 

- Session hijacking: Manipulating session expiry dates to extend or hijack sessions.

// Malicious session handling in a Safari plugin

safari.extension.addContentScript(`

    let sessionToken = {

        user: 'victimUser',

        expiry: new Date('2024-07-08T00:00:00Z')

    };

    // Attacker changes expiry date to a future date

    sessionToken.expiry = new Date('2025-07-08T00:00:00Z');

    // Use the manipulated token to maintain unauthorized access

    document.cookie = \`sessionToken=\${JSON.stringify(sessionToken)}\`;

`);

 

- Exploiting time zone differences: Manipulating time zone data within a Safari plugin to bypass date-based security mechanisms or logic.

// Malicious time zone manipulation in a Safari plugin

safari.extension.addContentScript(`

    function checkEventExpiry(eventDate) {

        let now = new Date();

        return now > new Date(eventDate);

    }

    

    let eventDate = '2024-07-08T00:00:00Z';

    // Attacker changes local time zone to bypass expiry check

    let manipulatedDate = new Date(new Date(eventDate).getTime() - 86400000); // 1 day earlier

    console.log(checkEventExpiry(manipulatedDate)); // False, event appears not expired

`);

 

- Format confusion for injection attacks: Failing to enforce consistent date formats can be exploited to inject malicious data or bypass validations.

// Malicious date format handling in a Safari plugin

safari.extension.addContentScript(`

    function processDate(inputDate) {

        let date = new Date(inputDate);

        // Further processing with the date

    }

    

    // Attacker provides date in a different format to exploit validation logic

    let maliciousDate = '2024-31-12'; // YYYY-DD-MM format

    processDate(maliciousDate);

`);

 

- Predictable date patterns for CSRF token generation: Exploiting predictable date patterns to forge valid CSRF tokens.

// Malicious CSRF token generation in a Safari plugin

safari.extension.addContentScript(`

    function generateCSRFToken() {

        let date = new Date();

        return btoa(date.toString());

    }

    

    // Attacker predicts the token based on known date patterns

    let predictedToken = btoa(new Date().toString());

    // Use the predicted token to perform CSRF attack

    fetch('/protectedAction', {

        method: 'POST',

        headers: { 'CSRF-Token': predictedToken }

    });

`);

Yep, security matters more than ever before

- Use HTTPS

Ensure all data transmissions are encrypted using HTTPS. This instantly prevents man-in-the-middle attacks and data tampering. Very easy.

- Avoid 'eval()' and similar functions

Instead of using 'eval()' or Function to execute strings as code, use safer alternatives like 'JSON.parse()' for parsing JSON data.

- Implement Content Security Policy (CSP)

A strong CSP helps prevent cross-site scripting (XSS) attacks. How does it do that? It restricts the sources from which your plugin can load resources. And you can easily define your CSP in the extension's manifest file - here's how:

json

{

  "content_security_policy": "default-src 'self'; script-src 'self'; object-src 'none';"

}

 

- Secure handling of user input

Validate and sanitize all user inputs to prevent injection attacks. Use libraries like DOMPurify to sanitize HTML input.

Privacy principles

- Minimize data collection

Collect only the data essential for your plugin's functionality. Avoid storing sensitive information unless absolutely necessary.

- Transparent data usage

Clearly communicate to users what data you collect, why you collect it, and how it will be used. Provide a detailed privacy policy.

- Anonymize data

Whenever possible, anonymize data to protect user identities. For example, if tracking usage statistics, use aggregated data rather than individual user data.

- User consent

Obtain explicit user consent before collecting or processing their data. This can be done through clear prompts and opt-in mechanisms.

Code quality and maintenance

- Use linters and static analysis tools

Incorporate tools like ESLint to enforce coding standards and detect potential security issues early in the development process.

- Regular security audits

Perform regular security audits of your codebase to identify and fix vulnerabilities. Use tools like Snyk to scan for known vulnerabilities in dependencies.

- Code reviews

Implement a thorough code review process. Peer reviews help catch security flaws and improve code quality.

- Keep dependencies updated

Regularly update third-party libraries and dependencies to their latest versions to mitigate known security vulnerabilities.

Secure data storage

- Use secure storage APIs

When storing sensitive data, use secure storage mechanisms. For instance, Safari extensions can use localStorage, but ensure sensitive data is encrypted before storage:

const encryptedData = btoa(unescape(encodeURIComponent(sensitiveData)));

localStorage.setItem('key', encryptedData);

 

- Handling cookies

Set cookies with appropriate attributes such as Secure and HttpOnly to enhance their security. Short and sweet example of use:

document.cookie = "name=value; Secure; HttpOnly; SameSite=Strict";

 

- Use IndexedDB for complex data

For more complex data storage needs, consider using IndexedDB, which provides a more robust and secure storage solution compared to localStorage. You'll see why.

Network security

- (Almost!) Never use cross-origin requests

Limit cross-origin requests to trusted domains only. Use CORS headers to control access to your plugin's resources.

- Secure WebSocket connections

If your plugin uses WebSockets, ensure connections are secured using wss:// (WebSocket Secure).

- API security

When interacting with APIs, always use secure authentication methods like OAuth. Ensure API keys and secrets are never exposed in the client-side code.

User interface security

- Avoid inline scripts and styles

Inline scripts and styles can be vulnerable to XSS attacks. Use external scripts and stylesheets instead.

- Safe DOM manipulation

When manipulating the DOM, use safe methods like textContent instead of innerHTML to avoid XSS vulnerabilities:

const element = document.createElement('div');

element.textContent = userInput;  // Safe

Performance optimization

- Optimize script loading

Load scripts asynchronously. Alternatively, you can defer them to improve page load times and performance - see the example:

<script src="plugin.js" async></script>

 

- Minimize resource usage

Make sure your plugin is efficient in terms of CPU and memory usage. Avoid long-running scripts, clean up event listeners and intervals when no longer needed.

- Efficient data handling

Web workers are great for computationally intensive tasks when you need to keep the main thread responsive.

Testing and monitoring

- Comprehensive testing

Use unit tests, integration tests, and end-to-end tests. These help us ensure the functionality and security of our plugins. And use frameworks like Jest and Selenium for testing. My recommendation.

- User feedback

Collect user feedback and act on it. This is proven useful to be able to continuously improve the plugin's security and functionality.

- Error monitoring

Sentry is great for error monitoring, for example. It serves to track and fix runtime errors in your plugin, and makes life easier!

0

Was this article helpful? Please, rate this.

There are no comments yet.
Authentication required

You must log in to post a comment.

Log in