alpinejs / alpine

A rugged, minimal framework for composing JavaScript behavior in your markup.
https://alpinejs.dev
MIT License
27.92k stars 1.22k forks source link

Improve Security Awareness #237

Closed WebReflection closed 4 years ago

WebReflection commented 4 years ago
for (const el of document.querySelectorAll('*')) {
  const attributes = [...el.attributes].filter(attr => '@click' === attr.name);
  if (attributes.length)
    attributes[0].value = 'alert("seriously? in 2020?")';
}

You can test it in codepen, and the attack regards any script that might be injected in a page that enabled evaluation for alpine.

I think the architecture behind alpine relies entirely on evaluation and deprecated ECMAScript features, and I am a libraries author myself, but I think it's about the time security becomes a major Web concern.

I am not sure how to fix this, as with(...) statement and evaluation of only the right thing would blow the size of this library, as it would require a proper AST crawling per each attribute content, but I hope this issue would be at least documented properly on top of the README page, as it's way too easy to inject arbitrary code when this library is trusted, and around.

Thanks for making the Web a better place.

ryangjchandler commented 2 years ago

The git documentation is the best place to start: https://git-scm.com/book/en/v2/Git-Tools-Submodules

mansoorkhan96 commented 2 years ago

The git documentation is the best place to start: https://git-scm.com/book/en/v2/Git-Tools-Submodules

Thanks @ryangjchandler I will try it.

thibaudcolas commented 2 years ago

I got really confused by the unavailability of the CSP build as well, so have proposed a PR to the documentation so it’s at least noted there this is still in progress: #2619.

JPGarCar commented 2 years ago

Any update on the availability of the CSP build? I am also unable to use this amazing library due to my strict CSP policy.

mittelgrau commented 2 years ago

Any recent development regarding the CSP-build?

stepanjakl commented 2 years ago

https://alpinejs.dev/advanced/csp, but I don't think it's released yet 🤷‍♂️

curtismorte commented 2 years ago

@stepanjakl looks like you can find the source code here: https://github.com/alpinejs/alpine/tree/main/packages/csp

I was just doing some testing with the CSP package.

When using x-data for reusable components, you can't pass initial parameters. Per the example from the CSP page:

<!-- Good -->
<div x-data="counter">
    <button @click="increment">Increment</button>

    <span x-text="count"></span>
</div>

<!-- Won't Work -->
<div x-data="counter(10)">
    <button @click="increment">Increment</button>

    <span x-text="count"></span>
</div>
// Works
Alpine.data('counter', () => ({
    count: 1,

    increment() { this.count++ }
}))

// Doesn't work
Alpine.data('counter', (initialValue) => ({
    count: initialValue,

    increment() { this.count++ }
}))

Thought I would share this. The issue here is passing values that can modify the data object which is used for the 'counter' value. Without looking into the code, my assumption is that the value counter(10) doesn't match with the key for data, thus, nothing happens. You could potentially do something like this however:

<!-- Good -->
<div x-data="counter" x-data-arguments='[10]'>
    <button @click="increment">Increment</button>

    <span x-text="count"></span>
</div>
Alpine.data('counter', () => ({
    count: 0,

    init() {
        let args = this.$el.getAttribute('x-data-arguments');
        if(args){
            try{
                args = JSON.parse(args);
                this.count = args[0];   
            } catch (e) {
                console.error('There was an issue parsing arguments for "counter". ', e);
            }
        }
    },

    increment() { this.count++ }
}))

The issue with this solution is that there is still potential to modify values prior to the initialization method happening. Albeit small, still something to point out. I don't see how this is any different than vanilla JS initializing something that gets its values via data attributes during initialization.

Has anyone else actually put the CSP to the test against legitimate use cases like I mentioned?

Yes I understand this requires you to build the repo from source.


Aside, you can build the repo from source by doing the following:

# Download source bundle (so many different ways to do this)
gh repo clone alpinejs/alpine

# Install packages
cd alpine && npm install

# Build Alpine
npm run build

Once you have done this, you can import Alpine like so (assuming you match your path):

// Alpine JS
import Alpine from '../../alpine/packages/csp';

// Make Alpine available to the rest of the components
window.Alpine = Alpine;

Alpine.data('counter', () => ({
    count: 0,

    init() {
        let args = this.$el.getAttribute('x-data-arguments');
        if(args){
            try{
                args = JSON.parse(args);
                this.count = args[0];
            } catch (e) {
                console.error('There was an issue parsing arguments for "counter". ', e);
            }
        }
    },

    increment() { this.count++ }
}));

/* -----------------------------------------------------------
 * Initialize Alpine after you have explicitly defined data
 * properties for all module includes.
 * ----------------------------------------------------------- */
Alpine.start();
gitRup-ca commented 1 year ago

Yes ... I am glad I found this thread after two days of research. Looks like I am sticking to more study time learning vanilla JS and building my own drop downs and modals etc. If Alpine.js is not an out-of-box strict CSP compliant solution ...no thanx. And no thanx to LiveWire too. Why would I want to learn advanced Alpine/LiveWire over a better understanding of vanilla JS ?

However, I did not come here just to complain.

May I suggest, instead of trying to fix ALL of Alpine.js for a strict CSP, just include some PREBUILT strict CSP compliant common needs.

For example; My client wanted a "hamburger" ( you know the three lines that drop a menu down) for logins etc on your cell phone. What I ended up doing to make it strict CSP compliant; is using JS onload to see if there is any html element with an ID of MainNavBar. If there was - then find out if there were any DIV ID's that matched NavMenu1 thru NavMeun9 on DIVs. This of course all being in an EXTERNAL JS file AND Nonce'd for the hell of it (no inline scripts). Done with Laravel Spatie - CSP, Tailwind and Blade components.

Now, if all I had to do was use STRICT Alpine.js/Blade SYNTAX and I got strict CSP...... SWEEEEEET HEAVEN !

Lets, consider the random website visitor. They come and get some nice tabs, nice carousal, tool tips, whatever is currently strict CSP possible. However, now they create an account and login. Some CSP gets relaxed. But now they opted for 2FA and THEY choose to relax the CSP opting for more interactivity. As the User becomes more VERIFIED I would like to give them more Alpine.js features. And now they are a verified 2FA with a verified credit card.

Just give me SOME strict CSP ...Alpine stuff AND let me choose when I will relax stuff. STOP trying to fix it all at once.

x-safe-hamburger-5menu-items requires DIV ID Parent blade component to be named EXACTLY as above there MUST BE EXACTLY - 5 child DIV's called EXACTLY x-div-item1 to EXACTLY x-div-item-5.

No less - no more.

Just give me some KEWL shit to make sales. STOP trying to fix it all at once.

x-safe-modal display blade msg John B.