Django XFrameOptionsMiddleware (X-Frame-Options) - allow iframe by client IP - django

I'm using Django XFrameOptionsMiddleware to control clickjacking, but I have a customer that needs to be able to browse the app in an iframe from within their network. I want to be able to apply (or remove) the xframe_options_exempt decorator from within the view method.

Best approach is to override get_xframe_options_value. XFRAME_EXEMPT_IPS is a glob_list in my case to detect allowable networks using fnmatch (192.168.*).
class TFXFrameOptionsMiddleware(XFrameOptionsMiddleware):
def get_xframe_options_value(self, request, response):
if request.META['REMOTE_ADDR'] in settings.XFRAME_EXEMPT_IPS:
return 'ALLOWALL' # non standard, equivalent to omitting
return getattr(settings, 'X_FRAME_OPTIONS', 'SAMEORIGIN').upper()

Related

Is there a way to restrict apps based on IP?

I'd like to be able to only allow certain apps to be used from the corporate office which has a static IP. Is there a django package that I can use to do this? If so do you know if it can be used as an additional security measure? Certain apps and the data in those apps I wouldnt want to be accessible by anyone outside the office. I already have pretty good app security but as an additional security measure is this a good option? Thanks
Just include this middleware class under the 'MIDDLEWARE_CLASSES' variable in your settings.py file.
Also include the variable BLOCKED_IPS = ('123.123.123.123',) variable, where the value is a tuple of IP addresses you want blocked from your site.
"""
simple middlware to block IP addresses via settings
variable BLOCKED_IPS
"""
from django.conf import settings
from django import http
class BlockedIpMiddleware(object):
def process_request(self, request):
if request.META['REMOTE_ADDR'] in settings.BLOCKED_IPS:
return http.HttpResponseForbidden('<h1>Forbidden</h1>')
return None
It looks like this is what I'm looking for...
django-iprestrict.readthedocs.io/en/latest/configuration.html
That package will let you either allow or deny by default and set IP whitelists or blacklists per app –
This is partly based on answer by Ramesh K, with changes for Django 2.2.19. On the server that I use: the load-balancer puts the IP address received into the "X-Real-IP" header (and also passes the "X-Forwarded-For" header as a comma-separated list of IP addresses). Then the "REMOTE_ADDR" contains load-balancer address, rather than the actual remote address.
from django.conf import settings
from django import http
class BlockedIpMiddleware:
def __init__(self, get_response):
# One-time configuration and initialization, when the webserver starts.
self.get_response = get_response
def __call__(self, request):
# Code to be executed for each request before the view (and later
# middleware) are called.
# if request.META['REMOTE_ADDR'] in settings.BLOCKED_IPS:
if request.META['HTTP_X_REAL_IP'] in settings.BLOCKED_IPS:
return http.HttpResponseForbidden('<h1>Forbidden</h1>')
return self.get_response(request)
There is a library I have been having my eye on, Django IP Restrict, I suggest you give a try and tell us your experiance too with it.

django-rest-framework authentication: require key parameter in URL?

I am working in Django 1.8 with the excellent django-rest-framework. I have a public RESTful API.
I would now like to start requiring a key GET parameter with this API, and disallowing any requests that do not have this parameter. I will allocate keys to users manually on request.
I have read through the DRF Authentication documentation, but I'm not sure there's anything that meets my use case. I find this strange, since my use case must be very common.
Token-based authentication requires the user to set an HTTP header. My typical API user is not sophisticated (Excel users who will be downloading CSVs), so I don't think I can ask them to do this.
I think Basic-Auth is what I need, but I'd much rather provide a simple URL-based key than a Django username and password (my app has no concept of users right now).
What is the best way to implement this?
Create a table which will contain all the keys that you issue to someone.
Example:
class RestApiKey(models.Model):
api_key = models.CharField(max_length=100)
Next create a custom Permision class which will check for the api Key in the url before forwarding the request to the view like:
from rest_framework import permissions
from yourappname.models import RestApiKey
class OnlyAPIPermission(permissions.BasePermission):
def has_permission(self, request, view):
try:
api_key = request.QUERY_PARAMS.get('apikey', False)
RestApiKey.objects.get(api_key=api_key)
return True
except:
return False
So the request url has to be like http://yourdomain.com/?apikey=sgvwregwrgwg
Next in your views add the permission class:
class YourViewSet(generics.ListAPIView):
permission_classes = (OnlyAPIPermission,)
or if you are using function based views then do like:
#permission_classes((OnlyAPIPermission, ))
def example_view(request, format=None):
. . .

What is the purpose of the psa decorator and how do we use it?

I've been using python-social-auth for a few weeks in a Django project. Now I am reaching the point where I need to authenticate a user from a view (that is, not through the template tags such as social:begin) and the documentation makes use of the psa() decorator from social.apps.django_app.utils.
I was not able to find anything that clearly explains what the psa decorator is supposed to do and the source from omab/python-social-auth does not provide any comment.
Can anyone explain:
What is the psa decorator supposed to do exactly?
What happens behind the scene when I use it to authenticate a user based on the access token retrieved by the front-end (possibly from any social network such as Facebook)?
Here's the code for psa (from here):
def psa(redirect_uri=None, load_strategy=load_strategy):
def decorator(func):
#wraps(func)
def wrapper(request, backend, *args, **kwargs):
uri = redirect_uri
if uri and not uri.startswith('/'):
uri = reverse(redirect_uri, args=(backend,))
request.social_strategy = load_strategy(request)
# backward compatibility in attribute name, only if not already
# defined
if not hasattr(request, 'strategy'):
request.strategy = request.social_strategy
try:
request.backend = load_backend(request.social_strategy,
backend, uri)
except MissingBackend:
raise Http404('Backend not found')
return func(request, backend, *args, **kwargs)
return wrapper
return decorator
As a decorator, it augments the function that it decorates.
It's doing three things:
Setting request.social_strategy (this object is framework-specific, eg, Django).
Setting request.backend (this object is specific to the authorization backend, eg, Facebook) based on the incoming backend string argument (eg, "facebook").
Providing a redirect URI or URI name (which is then "reversed" to get the URI) and passing the URI off to the backend so it knows where to redirect to when the time comes.
The decorated function can conveniently access request.social_strategy and request.backend and know that they will be set. See the Python Social Auth documentation for more information about what the Strategy and Backend are for.

Different type of anonymous users with Django

The Django project I'm currently working on is a website that should be accessed from a local network and the Internet. And part of the content should be available to anonymous users only if the visit the site from the local network (basically it's a test on the IP address), while authenticated users have access to the whole content.
I though about checking the IP as described here, but it seems to me quite bad to check the ip each time the user loads a page.
Is there a way to cleanly store user data even on anonymous user ? It would be nice to just be able to use a decorator like #login_required, but which would redirect only if the anonymous user has an external IP.
Actually, checking the ip on every requests seems to me to be one of the fastest methods available. Consider that the ip is already loaded in memory on every request, all you have to do is a simple dictionary lookup and a comparison, with a conditional string split/additional dict lookup. Compared to what happens on even the simplest page views, the performance impact is fully neglectable and comparable with the impact of using sessions or any other mechanism to save the ip.
You can write your own decorator function using user_passes_test:
from django.contrib.auth.decorators import user_passes_test
from django.utils.decorators import available_attrs
from functools import wraps
LOCAL_IPS = (
'127.0.0.1',
'other_ip',
'etc.',
)
def is_local_request(request):
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip in LOCAL_IPS
def local_ip_required(view_func):
def wrapped_view(request, *args, **kwargs):
if not is_local_request(request):
raise Http404 # or PermissionDenied or redirect
return view_func(request, *args, **kwargs)
return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)
Then simply use #local_ip_required. Note that this implementation will prevent both anonymous and logged-in users from accessing the view from an external location.

Limiting user to single app

I have a Django project with several apps. I'd like to restrict a particular user's access to only one specific app and at the time of the user's creation, i.e. without having to say modify every method of views.py with decorators such as #permission_required.
Is this possible? That is, is it possible to declare that user 'A' can only use app 'X' without modifying any of app 'Y's code?
You could write some middleware that implements the process_view method, then check which app the view function belongs to.
For example, this is one (potentially buggy) way you could do it:
class RestrictAppMiddleware(object):
def process_view(self, request, view_func, *args, **kwargs):
view_module = view_func.__module__
allowed_apps = apps_visible_to_user(request.user)
if not any(app_name in view_module for app_name in allowed_apps):
return HttpResponse("Not authorized", status=403)
Obviously you'd need to improve on the heuristic (ex, this one will allow users with access too "foo" view "foobar" as well) and consider apps which rely on Django built-in views (ex, direct_to_template)… But this is the way I'd do it.