Merge branch 'hotfix-sql-xss-injection' into dev

This commit is contained in:
Bubka 2023-06-30 17:01:04 +02:00
commit a51f0bb2d9
12 changed files with 88 additions and 17 deletions

19
.github/SECURITY.md vendored Normal file
View File

@ -0,0 +1,19 @@
## Reporting Security Issues
If you believe you have found a security vulnerability in 2FAuth, please report it through coordinated disclosure.
**Please do not report security vulnerabilities through the repository issues, discussions, or pull requests.**
Instead, please send an email to contact[at]2fauth.app or open a new [Github security advisory](https://github.com/Bubka/2FAuth/security/advisories/new).
Please include as much of the information listed below as you can to help me better understand and resolve the issue:
* The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting)
* Full paths of source file(s) related to the manifestation of the issue
* The location of the affected source code (tag/branch/commit or direct URL)
* Any special configuration required to reproduce the issue
* Step-by-step instructions to reproduce the issue
* Proof-of-concept or exploit code (if possible)
* Impact of the issue, including how an attacker might exploit the issue
This information will help me triage your report more quickly.

View File

@ -2,6 +2,7 @@
namespace App\Api\v1\Controllers; namespace App\Api\v1\Controllers;
use App\Api\v1\Requests\IconFetchRequest;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Models\TwoFAccount; use App\Models\TwoFAccount;
use App\Services\LogoService; use App\Services\LogoService;
@ -34,13 +35,11 @@ class IconController extends Controller
* *
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
*/ */
public function fetch(Request $request, LogoService $logoService) public function fetch(IconFetchRequest $request, LogoService $logoService)
{ {
$this->validate($request, [ $validated = $request->validated();
'service' => 'string|regex:/^[^:]+$/i',
]);
$icon = $logoService->getIcon($request->service); $icon = $logoService->getIcon($validated['service']);
return $icon return $icon
? response()->json(['filename' => $icon], 201) ? response()->json(['filename' => $icon], 201)

View File

@ -28,7 +28,7 @@ class GroupStoreRequest extends FormRequest
return [ return [
'name' => [ 'name' => [
'required', 'required',
'string', 'regex:/^[a-zA-Z0-9\s\-_]+$/',
'max:32', 'max:32',
Rule::unique('groups')->where(fn ($query) => $query->where('user_id', $this->user()->id)), Rule::unique('groups')->where(fn ($query) => $query->where('user_id', $this->user()->id)),
], ],

View File

@ -0,0 +1,45 @@
<?php
namespace App\Api\v1\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class IconFetchRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'service' => 'string|regex:/^[^:]+$/i',
];
}
/**
* Prepare the data for validation.
*
* @codeCoverageIgnore
*
* @return void
*/
protected function prepareForValidation()
{
$this->merge([
'service' => strip_tags($this->service),
]);
}
}

View File

@ -27,7 +27,7 @@ class CaseInsensitiveEmailExists implements Rule
public function passes($attribute, $value) public function passes($attribute, $value)
{ {
$user = DB::table('users') $user = DB::table('users')
->whereRaw('email = \'' . strtolower($value) . '\'' . ('sqlite' === config('database.default') ? ' COLLATE NOCASE' : '')) ->whereRaw('email = ?' . ('sqlite' === config('database.default') ? ' COLLATE NOCASE' : ''), [strtolower($value)])
->first(); ->first();
return ! $user ? false : true; return ! $user ? false : true;

View File

@ -21,6 +21,13 @@ This new version introduces a very common feature in the 2FA app world
- [issue #180](https://github.com/Bubka/2FAuth/issues/180) OTP does not rotate while close after copy and copy on display is activated - By [@josh-gaby](https://github.com/josh-gaby) - [issue #180](https://github.com/Bubka/2FAuth/issues/180) OTP does not rotate while close after copy and copy on display is activated - By [@josh-gaby](https://github.com/josh-gaby)
- [issue #194](https://github.com/Bubka/2FAuth/issues/194) Container keeps trying to make connection to 172.67.161.186 - [issue #194](https://github.com/Bubka/2FAuth/issues/194) Container keeps trying to make connection to 172.67.161.186
## [4.0.3] - 2023-06-30
### Security release
- Fix possible SQL injection in validation rule (thx [@YouGina](https://github.com/YouGina))
- Fix various possible XSS injections (thx [@quirinziessler](https://github.com/quirinziessler))
## [4.0.2] - 2023-04-19 ## [4.0.2] - 2023-04-19
### Fixed ### Fixed

2
public/js/app.js vendored

File diff suppressed because one or more lines are too long

View File

@ -3,4 +3,4 @@
"/js/manifest.js": "/js/manifest.js?id=af5ab3286fe62cebba2085465b83b8b5", "/js/manifest.js": "/js/manifest.js?id=af5ab3286fe62cebba2085465b83b8b5",
"/css/app.css": "/css/app.css?id=0b5ae8b0a2a672fb4bdcb89779f40bb8", "/css/app.css": "/css/app.css?id=0b5ae8b0a2a672fb4bdcb89779f40bb8",
"/js/vendor.js": "/js/vendor.js?id=4061d7dc1f13572332a3e7eff0d873dd" "/js/vendor.js": "/js/vendor.js?id=4061d7dc1f13572332a3e7eff0d873dd"
} }

View File

@ -137,6 +137,10 @@ Vue.mixin({
} }
return this.$root.userPreferences.showOtpAsDot ? pwd.replace(/[0-9]/g, '●') : pwd return this.$root.userPreferences.showOtpAsDot ? pwd.replace(/[0-9]/g, '●') : pwd
}, },
strip_tags (str) {
return str.replace(/(<([^> ]+)>)/ig, "")
}
} }
}) })

View File

@ -149,7 +149,7 @@
<div class="block"> <div class="block">
{{ $t('errors.data_of_qrcode_is_not_valid_URI') }} {{ $t('errors.data_of_qrcode_is_not_valid_URI') }}
</div> </div>
<div class="block mb-6" :class="$root.showDarkMode ? 'has-text-light':'has-text-grey-dark'" v-html="uri"></div> <div class="block mb-6" :class="$root.showDarkMode ? 'has-text-light':'has-text-grey-dark'">{{ uri }}</div>
<!-- Copy to clipboard --> <!-- Copy to clipboard -->
<div class="block has-text-link"> <div class="block has-text-link">
<button class="button is-link is-outlined is-rounded" v-clipboard="() => uri" v-clipboard:success="clipboardSuccessHandler"> <button class="button is-link is-outlined is-rounded" v-clipboard="() => uri" v-clipboard:success="clipboardSuccessHandler">
@ -377,10 +377,10 @@
this.deleteIcon() this.deleteIcon()
this.tempIcon = response.data.filename; this.tempIcon = response.data.filename;
} }
else this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.form.service}) }) else this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.strip_tags(this.form.service)}) })
}) })
.catch(error => { .catch(error => {
this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.form.service}) }) this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.strip_tags(this.form.service)}) })
}); });
} }
}, },

View File

@ -265,10 +265,10 @@
this.deleteIcon() this.deleteIcon()
this.tempIcon = response.data.filename; this.tempIcon = response.data.filename;
} }
else this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.form.service}) }) else this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.strip_tags(this.form.service)}) })
}) })
.catch(error => { .catch(error => {
this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.form.service}) }) this.$notify({type: 'is-warning', text: this.$t('errors.no_logo_found_for_x', {service: this.strip_tags(this.form.service)}) })
}); });
} }
}, },

View File

@ -105,9 +105,6 @@ class GroupStoreRequestTest extends FeatureTestCase
[[ [[
'name' => true, // string 'name' => true, // string
]], ]],
[[
'name' => 8, // string
]],
[[ [[
'name' => 'mmmmmmoooooorrrrrreeeeeeettttttthhhhhhaaaaaaannnnnn32cccccchhhhhaaaaaarrrrrrsssssss', // max:32 'name' => 'mmmmmmoooooorrrrrreeeeeeettttttthhhhhhaaaaaaannnnnn32cccccchhhhhaaaaaarrrrrrsssssss', // max:32
]], ]],