I run laravel application on AWS Elasticbeanstalk, I use Application Load Balancer.
Route::get('/what-is-my-ip', function(){
return request()->ip();
});
When I run this code, my ip doesn't show, it shows the load balancer's ip addresses.
Those who used the same problem with cloudflare also experienced and have solutions for cloudflare, but I couldn't find a solution for the AWS Application Load Balancer.
I am having trouble getting users' ip addresses and adding --allow-ip in maintenance mode.
function real_IP() {
$real_IP = '';
if (getenv('HTTP_CLIENT_IP'))
$real_IP = getenv('HTTP_CLIENT_IP');
else if(getenv('HTTP_X_FORWARDED_FOR'))
$real_IP = getenv('HTTP_X_FORWARDED_FOR');
else if(getenv('HTTP_X_FORWARDED'))
$real_IP = getenv('HTTP_X_FORWARDED');
else if(getenv('HTTP_FORWARDED_FOR'))
$real_IP = getenv('HTTP_FORWARDED_FOR');
else if(getenv('HTTP_FORWARDED'))
$real_IP = getenv('HTTP_FORWARDED');
else if(getenv('REMOTE_ADDR'))
$real_IP = getenv('REMOTE_ADDR');
else
$real_IP = 'UNKNOWN';
return $real_IP;
}
when i run this code it gives the correct ip address, i want to fix it across laravel.
You'll need to trust the AWS load balancers as a proxy.
If you are using AWS Elastic Load Balancing, your $headers value should be Request::HEADER_X_FORWARDED_AWS_ELB. For more information on the constants that may be used in the $headers property, check out Symfony's documentation on trusting proxies.
If you are using Amazon AWS or another "cloud" load balancer provider,
you may not know the IP addresses of your actual balancers. In this
case, you may use * to trust all proxies:
protected $proxies = '*';
Two common issues when you use AWS or any other cloud Load Balancer:
HTTPS (Laravel asset and route): You applied SSL/TLS and the URL is protected in the browser but Laravel doesn't load your asset and throw an error. The error look like it blocks the URLS because of you are trying to load http URL http request. Most of the people facing this issue when use AWS or any other cloud Load Balancer. When running your applications behind a load balancer that terminates TLS / SSL certificates, you may notice your application sometimes does not generate HTTPS links when using the url helper. Typically this is because your application is being forwarded traffic from your load balancer on port 80 and does not know it should generate secure links.
IP: Another issue is IP issue. You can't get the user/visitor IP and it returns always server IP. This issue also happen because of proxies.
Solution: When you are using AWS or any cloud Load Balancer then you may not know the exact IP address of your actual Loads Balancer so should allow all proxies like below example.
Use * to allow trust all proxies in your TrustProxies middleware. Here is your middleware app/Http/Middlewares/TrustProxies.php.
namespace App\Http\Middleware;
use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* #var string|array
*/
protected $proxies = '*';
/**
* The headers that should be used to detect proxies.
*
* #var int
*/
protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO;
If you are using AWS Elastic Load Balancing, your $headers value should be Request::HEADER_X_FORWARDED_AWS_ELB. For more information on the constants that may be used in the $headers property, check out Symfony's documentation on trusting proxies.
namespace App\Http\Middleware;
use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Request;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* #var array|string
*/
protected $proxies = '*';
/**
* The headers that should be used to detect proxies.
*
* #var int
*/
protected $headers = Request::HEADER_X_FORWARDED_AWS_ELB;
I think it solves your HTTPS, IP and other proxy related issue. To read more details read Laravel doc. If you face any other issue or need improvements comments below.
Related
Hello … l am finish Building website using Laravel and jQuery and bootstrap it's working good in local but when I upload to Heroku the file jQuery and bootstrap not working … it's work in local using http but in Heroku its need https its not working but when write http substitute of https it's working good like local and display Not Secure .. now any body know how can i allow website using https in Heroku or How can selection this problem
You should closely read all of Heroku's guide to getting started with Laravel.
The section titled "Trusting the Load Balancer" will resolve your issues.
Because of this:
This means that requests received by a dyno will have the last router’s IP address in the REMOTE_ADDR environment variable, and the internal request will always be made using the HTTP protocol, even if the original request was made over HTTPS.
Laravel sees HTTP requests coming in to the application, so it serves HTTP URLs for your various routes and asset URLs. As far as it knows, you're browsing via HTTP. The fix is to trust Heroku's "forwarded for" headers in your app's App\Http\Middleware\TrustProxies middleware:
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Fideloper\Proxy\TrustProxies as Middleware;
class TrustProxies extends Middleware
{
protected $proxies = '*';
protected $headers = Request:: HEADER_X_FORWARDED_AWS_ELB;
}
Had this issue myself awhile back, there are a few options and some are more heavy handed than others. If you want to gauruntee that everything is always https no exceptions first update your APP_URL to 'https://example.com' then in the boot method of your AppServiceProvider add Url::forceScheme('https');
The less heavy handed option is to find all of the places you use the asset() helper and change it to secure_asset instead. The asset helper should use your APP_URL to know the request is https but in my experience I couldn't rely on that so use secure_asset to make sure
Hello … l am finish Building website using Laravel and jQuery and bootstrap it's working good in local but when I upload to Heroku the file jQuery and bootstrap not working … it's work in local using http but in Heroku its need https its not working but when write http substitute of https it's working good like local and display Not Secure .. now any body know how can i allow website using https in Heroku or How can selection this problem
You should closely read all of Heroku's guide to getting started with Laravel.
The section titled "Trusting the Load Balancer" will resolve your issues.
Because of this:
This means that requests received by a dyno will have the last router’s IP address in the REMOTE_ADDR environment variable, and the internal request will always be made using the HTTP protocol, even if the original request was made over HTTPS.
Laravel sees HTTP requests coming in to the application, so it serves HTTP URLs for your various routes and asset URLs. As far as it knows, you're browsing via HTTP. The fix is to trust Heroku's "forwarded for" headers in your app's App\Http\Middleware\TrustProxies middleware:
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Fideloper\Proxy\TrustProxies as Middleware;
class TrustProxies extends Middleware
{
protected $proxies = '*';
protected $headers = Request:: HEADER_X_FORWARDED_AWS_ELB;
}
Had this issue myself awhile back, there are a few options and some are more heavy handed than others. If you want to gauruntee that everything is always https no exceptions first update your APP_URL to 'https://example.com' then in the boot method of your AppServiceProvider add Url::forceScheme('https');
The less heavy handed option is to find all of the places you use the asset() helper and change it to secure_asset instead. The asset helper should use your APP_URL to know the request is https but in my experience I couldn't rely on that so use secure_asset to make sure
Almost all Laravel projects hosted on Github use use Illuminate\Contracts\Console\Kernel; Console Kernel to create an application/ for bootstrapping the whole app for testing using vendor/bin/phpunit
For example this is the Voten laravel application
https://github.com/voten-co/voten/blob/master/tests/CreatesApplication.php
<?php
namespace Tests;
use Illuminate\Contracts\Console\Kernel;
trait CreatesApplication
{
/**
* Creates the application.
*
* #return \Illuminate\Foundation\Application
*/
public function createApplication()
{
$app = require __DIR__.'/../bootstrap/app.php';
$app->make(Kernel::class)->bootstrap();
return $app;
}
}
I wonder why we don't use the use Illuminate\Contracts\Http\Kernel;
Is that because vendor/bin/phpunit starts normally within the commandline, so it's a requirement to use the Console Kernel instead of the Http one? I have searched online for the reason why is it like, but I didn't find an answer.
I know the difference between the two Kernels and when each one is being used. Here is a good answer about the difference between the two of them
How to use Console Kernel is Laravel PHP?
I am sure there is a good reason for using Console Kernel for testing! But I don't why, can anyone explain that for me?
And is it possible then to use the Http Kernel instead of the Console kernel?
I am overriding the rendering of a couple of exceptions in the App\Exceptions\Handler so I can return custom error pages. However, on some of the exceptions the auth()->user() is not set.
In the render-method, I am just dumping the user like this:
public function render($request, Exception $exception)
{
dd(auth()->user());
return parent::render($request, $exception);
}
When the exceptions are of the type NotFoundHttpException, the user isn't set. What would be the best solution for getting the user in these exceptions?
Here's the solution, but read on for a different recommendation.
By default, Laravel's authentication runs via the session. The session is explicitly started in the web middleware group.
If a route is not wrapped in the web middleware group (as a non-existent / 404 route would be), the middleware doesn't run, and the session isn't started. Therefore Laravel can't know if there is a session user.
Best solution: define a fallback route which was built for exactly this purpose.
Another solution, with gotchas: move the StartSession middleware into the global group that runs on every request.
/app/Http/Kernel.php:
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* #var array
*/
protected $middleware = [
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
// +++ MOVED SESSION START HERE BELOW +++
\Illuminate\Session\Middleware\StartSession::class,
];
But, should you...?
First, there's a reason the session doesn't load on every request by default: it creates extra overhead that might not be needed on every request. For example, if your website is configured to always use Laravel as the request handler, every 404 will route through Laravel. And there are a lot - crawlers and bots are constantly scouring the web for known insecure web paths. Take a look at your access logs.
Also, if you create self-contained error pages that don't depend on external application logic, you can reuse them at the server level. If Apache or Nginx throws an error, Laravel won't be there at all to dictate the output.
TL;DR: You can enable sessions on 404 and other pages, but understand the trade-offs. Personally, I recommend avoiding application logic on error pages.
Try:
Auth::user()
It should work the same way. Make sure you're including the Auth library.
My server uses SSL and thus all my routes/urls use https. I recently discovered a bug in Laravel 5.7 which was exposed when trying to use Email Verification, which does not work on a server with https. I wont go into the specifics of that problem as I have another question for that. I want to keep this simple.
I have the following settings in my .env file:
APP_USE_HTTPS=true
APP_URL=https://www.example.com
APP_ENV=production
And I have the following in the boot() method of the AppServiceProvider
if (env('APP_USE_HTTPS')) {
Log::info('AppServiceProvider: forcing URLs to use https');
URL::forceScheme('https');
}
And it may be overkill but to try to resolve the issue I also put the following code at the top of my web.php routes file"
if (env('APP_USE_HTTPS')) {
Log::info('Routes: forcing URLs to use https');
URL::forceScheme('https');
}
Route::get('/', 'PublicController#getHome');
Route::get('home', 'PublicController#getHome');
Then in my PublicController.getHome() method I put this code:
public function getHome()
{
$currentPath= Request::fullUrl();
Log::info($currentPath);
return view('public.home');
}
Now I go to my browser and enter this in the address bar:
https://www.example.com
And I get this in my log file:
AppServiceProvider: forcing URLs to use https
Routes: forcing URLs to use https
http://www.example.com
So as you can see from the last log message the fact that laravel always uses http instead of https is beginning to create issues. Starting with signed routes. I am trying to use the built-in Email Verification but the signature is being generated using https route and the email sent to user does have https in the url for going back to the same server. However the validation for the route is using http (even though https was used) so it generates a different signature and thus all verifications links fail with a 403 error.
Is there anything I am missing? I can't seem to find code that shows me how Laravel knows to use https or http or is it just hard coded for http?
Thanks for any help you can give me.
*** Update to show problem with Shaielndra Gupta answer ****
After implementing the middleware below is the code I used but as you will see the core problem exists in ALL methods dealing with url. So for example:
$request->secure()
returns false even when https was used. Then by calling:
redirect()->secure($request->getRequestUri());
does no good because that will cause the route to loop back into this method again which still returns false for secure(), basically creating an infinite loop (or infinite too many redirects)
class ForceHttpsProtocol {
public function handle($request, Closure $next) {
Log::info('request uri: '.$request->fullUrl());
Log::info('secure: '.($request->secure() ? 'yes' : 'no'));
if (!$request->secure() && env('APP_USE_HTTPS')) {
return redirect()->secure($request->getRequestUri());
}
return $next($request);
}
}
The log from the above code will produce the following when you make 1 attempt to go to any page even when using https://www.example.com
request uri: http://www.example.com
secure: no
request uri: http://www.example.com
secure: no
request uri: http://www.example.com
secure: no
request uri: http://www.example.com
secure: no
< over and over till page times out >
After much research I finally discovered what the issue is.
My live server is installed on an Amazon EC2 server which is behind a Load Balancer.
The load balancer is receiving the (https) request and handling all the SSL requirements and then forwarding the request to my website as http.
To fix this issue I had to install the fideloper/TrustedProxy package. This package allows my site to trust the proxy and get the valid headers for the request so it now knows the request was actually sent using https.
Laravel wrote an article which describes my condition exactly.
https://laravel-news.com/trusted-proxy
This is the package I installed:
https://github.com/fideloper/TrustedProxy
change in your config/session.php
'http_only' => true,
change it to
'http_only' => false,
or make a middlewere HttpsProtocol.php
namespace MyApp\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\App;
class HttpsProtocol {
public function handle($request, Closure $next)
{
if (!$request->secure() && App::environment() === 'production')
{
return redirect()->secure($request->getRequestUri());
}
return $next($request);
}
}
Then, apply this middleware to every request adding setting the rule at Kernel.php file in protected $routeMiddleware array,
'https'=>App\Http\Middleware\HttpsProtocol::class
change This
APP_USE_HTTPS=true
APP_URL=https://www.example.com
to this
APP_URL=http://www.example.com
APP_USE_HTTPS=false
Because Laravel uses APP_URL to generate urls.