esamattis / underscore.string

String manipulation helpers for javascript
http://esamattis.github.com/underscore.string/
3.37k stars 375 forks source link

Try to fix regexp ReDoS #517

Closed esamattis closed 6 years ago

esamattis commented 6 years ago

Fixes #510.

Can you @cristianstaicu review this?

jpw commented 6 years ago

Hiya, sorry was just having a look out of interest.

const Benchmark = require('benchmark');
const suite = new Benchmark.Suite;

const haystack = '2&5'.repeat(7142); // appx 50k chars

suite.add('rexPlus', () => {
    haystack.replace(/\&([^;]+);/g, 0)
}, {
    minSamples:500
});

suite.add('rexBrace', () => {
    haystack.replace(/\&([^;]{1,10});/g, 0)
}, {
    minSamples:500
});

suite.on('cycle', function(event) {
    console.log(String(event.target));
  })
  .on('complete', function() {
    console.log('Fastest is ' + this.filter('fastest').map('name'));
  })

suite.run();

/*
output:
    rexPlus x 3,323 ops/sec ±0.42% (588 runs sampled)
    rexBrace x 3,080 ops/sec ±0.30% (588 runs sampled)
    Fastest is rexPlus
*/

It actually seems a bit slower, but little difference.

To be honest I don't think there's anything particularly wrong with the regexp and I couldn't find a way of optimising it. I'm no regexp expert but the best option may be to slice up large input strings and process them in batches..?

esamattis commented 6 years ago

Yeah, you're there's no real difference in that case...

janotav commented 5 years ago

I know I'm late to the party, but since this ticket helped me (hopefully) understand the nature of the issue here is my contribution should anyone stumble upon this again:

const haystack = '&'.repeat(50000) + 'solong'; // appx 50k chars 

This is an example of a haystack where the DoS is pronounced.