Skip to content

Commit 40579ba

Browse files
[5.5] Security fixes (#33858)
* fix casing issue with guarded * block json mass assignment * formatting * add boolean * protect table names and guarded * Apply fixes from StyleCI (#33772) * dont allow mass filling with table names * Apply fixes from StyleCI (#33773) * [6.x] Verify column names are actual columns when using guarded (#33777) * verify column names are actual columns when using guarded * Apply fixes from StyleCI (#33778) * remove json check * Apply fixes from StyleCI (#33857) Co-authored-by: Taylor Otwell <taylorotwell@gmail.com> Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent a81f23d commit 40579ba

File tree

7 files changed

+75
-7
lines changed

7 files changed

+75
-7
lines changed

src/Illuminate/Database/Eloquent/Concerns/GuardsAttributes.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ trait GuardsAttributes
2727
*/
2828
protected static $unguarded = false;
2929

30+
/**
31+
* The actual columns that exist on the database and can be guarded.
32+
*
33+
* @var array
34+
*/
35+
protected static $guardableColumns = [];
36+
3037
/**
3138
* Get the fillable attributes for the model.
3239
*
@@ -152,6 +159,7 @@ public function isFillable($key)
152159
}
153160

154161
return empty($this->getFillable()) &&
162+
strpos($key, '.') === false &&
155163
! Str::startsWith($key, '_');
156164
}
157165

@@ -163,7 +171,30 @@ public function isFillable($key)
163171
*/
164172
public function isGuarded($key)
165173
{
166-
return in_array($key, $this->getGuarded()) || $this->getGuarded() == ['*'];
174+
if (empty($this->getGuarded())) {
175+
return false;
176+
}
177+
178+
return $this->getGuarded() == ['*'] ||
179+
! empty(preg_grep('/^'.preg_quote($key).'$/i', $this->getGuarded())) ||
180+
! $this->isGuardableColumn($key);
181+
}
182+
183+
/**
184+
* Determine if the given column is a valid, guardable column.
185+
*
186+
* @param string $key
187+
* @return bool
188+
*/
189+
protected function isGuardableColumn($key)
190+
{
191+
if (! isset(static::$guardableColumns[get_class($this)])) {
192+
static::$guardableColumns[get_class($this)] = $this->getConnection()
193+
->getSchemaBuilder()
194+
->getColumnListing($this->getTable());
195+
}
196+
197+
return in_array($key, static::$guardableColumns[get_class($this)]);
167198
}
168199

169200
/**

src/Illuminate/Database/Eloquent/Model.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ public function qualifyColumn($column)
272272
*/
273273
protected function removeTableFromKey($key)
274274
{
275-
return Str::contains($key, '.') ? last(explode('.', $key)) : $key;
275+
return $key;
276276
}
277277

278278
/**

src/Illuminate/Queue/Listener.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ public function memoryExceeded($memoryLimit)
232232
*/
233233
public function stop()
234234
{
235-
die;
235+
exit;
236236
}
237237

238238
/**

src/Illuminate/Support/Collection.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ public function dd(...$args)
275275

276276
call_user_func_array([$this, 'dump'], $args);
277277

278-
die(1);
278+
exit(1);
279279
}
280280

281281
/**

src/Illuminate/Support/helpers.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ function dd(...$args)
559559
(new Dumper)->dump($x);
560560
}
561561

562-
die(1);
562+
exit(1);
563563
}
564564
}
565565

tests/Database/DatabaseEloquentModelTest.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -919,11 +919,21 @@ public function testUnderscorePropertiesAreNotFilled()
919919
public function testGuarded()
920920
{
921921
$model = new EloquentModelStub;
922+
923+
EloquentModelStub::setConnectionResolver($resolver = m::mock('Illuminate\Database\ConnectionResolverInterface'));
924+
$resolver->shouldReceive('connection')->andReturn($connection = m::mock(stdClass::class));
925+
$connection->shouldReceive('getSchemaBuilder->getColumnListing')->andReturn(['name', 'age', 'foo']);
926+
922927
$model->guard(['name', 'age']);
923928
$model->fill(['name' => 'foo', 'age' => 'bar', 'foo' => 'bar']);
924929
$this->assertFalse(isset($model->name));
925930
$this->assertFalse(isset($model->age));
926-
$this->assertEquals('bar', $model->foo);
931+
$this->assertSame('bar', $model->foo);
932+
933+
$model = new EloquentModelStub;
934+
$model->guard(['name', 'age']);
935+
$model->fill(['Foo' => 'bar']);
936+
$this->assertFalse(isset($model->Foo));
927937
}
928938

929939
public function testFillableOverridesGuarded()
@@ -1829,7 +1839,7 @@ public function getDates()
18291839
class EloquentModelSaveStub extends Model
18301840
{
18311841
protected $table = 'save_stub';
1832-
protected $guarded = ['id'];
1842+
protected $guarded = [];
18331843

18341844
public function save(array $options = [])
18351845
{

tests/Integration/Database/EloquentModelTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,33 @@ public function setUp()
2626
});
2727
}
2828

29+
public function test_cant_update_guarded_attributes_using_different_casing()
30+
{
31+
$model = new TestModel2;
32+
33+
$model->fill(['ID' => 123]);
34+
35+
$this->assertNull($model->ID);
36+
}
37+
38+
public function test_cant_update_guarded_attribute_using_json()
39+
{
40+
$model = new TestModel2;
41+
42+
$model->fill(['id->foo' => 123]);
43+
44+
$this->assertNull($model->id);
45+
}
46+
47+
public function test_cant_mass_fill_attributes_with_table_names_when_using_guarded()
48+
{
49+
$model = new TestModel2;
50+
51+
$model->fill(['foo.bar' => 123]);
52+
53+
$this->assertCount(0, $model->getAttributes());
54+
}
55+
2956
public function test_user_can_update_nullable_date()
3057
{
3158
$user = TestModel1::create([

0 commit comments

Comments
 (0)