मुझे django में उपयोगकर्ता IP पता कैसे मिलेगा?


287

मुझे django में उपयोगकर्ता का IP कैसे मिलेगा?

मेरे पास इस तरह का एक दृश्य है:

# Create your views
from django.contrib.gis.utils import GeoIP
from django.template import  RequestContext
from django.shortcuts import render_to_response


def home(request):
  g = GeoIP()
  client_ip = request.META['REMOTE_ADDR']
  lat,long = g.lat_lon(client_ip)
  return render_to_response('home_page_tmp.html',locals())

लेकिन मुझे यह त्रुटि मिली:

KeyError at /mypage/
    'REMOTE_ADDR'
    Request Method: GET
    Request URL:    http://mywebsite.com/mypage/
    Django Version: 1.2.4
    Exception Type: KeyError
    Exception Value:    
    'REMOTE_ADDR'
    Exception Location: /mysite/homepage/views.py in home, line 9
    Python Executable:  /usr/bin/python
    Python Version: 2.6.6
    Python Path:    ['/mysite', '/usr/local/lib/python2.6/dist-packages/flup-1.0.2-py2.6.egg', '/usr/lib/python2.6', '/usr/lib/python2.6/plat-linux2', '/usr/lib/python2.6/lib-tk', '/usr/lib/python2.6/lib-old', '/usr/lib/python2.6/lib-dynload', '/usr/local/lib/python2.6/dist-packages', '/usr/lib/python2.6/dist-packages', '/usr/lib/pymodules/python2.6']
    Server time:    Sun, 2 Jan 2011 20:42:50 -0600

2
डंपिंग अनुरोध का प्रयास करें
। META.keys

2
[ 'HTTP_COOKIE', 'स्क्रिप्ट', 'REQUEST_METHOD', 'PATH_INFO', 'SERVER_PROTOCOL', 'QUERY_STRING', 'CONTENT_LENGTH', 'HTTP_ACCEPT_CHARSET', 'HTTP_USER_AGENT', 'HTTP_CONNECTION', 'SERVER_NAME', 'wsgi.url_scheme' , 'SERVER_PORT', 'wsgi.input', 'HTTP_HOST', 'wsgi.multithread', 'HTTP_CACHE_CONTROL', 'HTTP_ACCEPT', 'wsgi.version', 'wsgi.run_once', 'wsgi.errors', 'wsgi.errors'। मल्टीप्रोसेस ',' HTTP_ACCEPT_LANGUAGE ',' CONTENT_TYPE ',' CSRF_COOKIE ',' HTTP_ACCEPT_ENCODING ']
अवतार

2
इस बेहतरीन सवाल के लिए धन्यवाद। मेरी Fastcgi REMOTE_ADDR मेटा कुंजी पास नहीं कर रही थी। मैंने नीचे nginx.conf में लाइन जोड़ी और समस्या को ठीक किया: fastcgi_param REMOTE_ADDR $ Remote_addr;
अवतार

जवाबों:


435
def get_client_ip(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

सुनिश्चित करें कि आपके पास रिवर्स प्रॉक्सी (यदि कोई है) सही तरीके से कॉन्फ़िगर किया गया है (जैसे mod_rpafअपाचे के लिए स्थापित)।

ध्यान दें: ऊपर का उपयोग करता है पहले में आइटम X-Forwarded-Forहै, लेकिन आप का उपयोग करना चाहें पिछले मद (Heroku के मामले में, उदाहरण के लिए: Heroku पर ग्राहक की वास्तविक आईपी पते प्राप्त करें )

और फिर अनुरोध को केवल तर्क के रूप में पारित करें;

get_client_ip(request)

8
ip = get_client_ip(request)अपने दृश्य फ़ंक्शन में कॉल करें।
yanchenko

4
वास्तविक ग्राहक IP पता HTTP_X_FORWARDED_FOR में पहला (अंतिम नहीं) है (विकिपीडिया पृष्ठ देखें)
jujule

5
@ जुजुले यह सही नहीं है। प्रारूप आमतौर पर है X-Forwarded-For: client, proxy1, proxy2। तो पहला पता क्लाइंट का है।
माइकल वाटरफॉल

51
यह कार्य खतरनाक है। कई सेटअपों के साथ एक दुर्भावनापूर्ण उपयोगकर्ता आसानी से इस फ़ंक्शन को अपने वास्तविक पते के बजाय किसी भी पते पर वापस लौट सकता है। देखें esd.io/blog/flask-apps-heroku-real-ip-spoofing.html
एली

8
Django डॉक्स से ( "REMOTE_ADDR या इसी तरह के मूल्यों पर निर्भर व्यापक रूप से एक सबसे खराब अभ्यास के रूप में जाना जाता है" djangoproject.com/weblog/2009/jul/28/security/#secondary-issue )
zags

209

आप django-ipware का उपयोग कर सकते हैं जो Python 2 और 3 का समर्थन करता है और IPv4 & IPv6 को संभालता है ।

इंस्टॉल:

pip install django-ipware

सरल उपयोग:

# In a view or a middleware where the `request` object is available

from ipware import get_client_ip
ip, is_routable = get_client_ip(request)
if ip is None:
    # Unable to get the client's IP address
else:
    # We got the client's IP address
    if is_routable:
        # The client's IP address is publicly routable on the Internet
    else:
        # The client's IP address is private

# Order of precedence is (Public, Private, Loopback, None)

उन्नत उपयोग:

  • कस्टम हैडर - आईपीवेयर के लिए कस्टम अनुरोध हेडर को देखने के लिए:

    i, r = get_client_ip(request, request_header_order=['X_FORWARDED_FOR'])
    i, r = get_client_ip(request, request_header_order=['X_FORWARDED_FOR', 'REMOTE_ADDR'])
  • प्रॉक्सी काउंट - एक निश्चित संख्या के पीछे Django सर्वर है:

    i, r = get_client_ip(request, proxy_count=1)
  • विश्वसनीय प्रॉक्सी - Django सर्वर एक या अधिक ज्ञात और विश्वसनीय प्रॉक्सी के पीछे है:

    i, r = get_client_ip(request, proxy_trusted_ips=('177.2.2.2'))
    
    # For multiple proxies, simply add them to the list
    i, r = get_client_ip(request, proxy_trusted_ips=('177.2.2.2', '177.3.3.3'))
    
    # For proxies with fixed sub-domain and dynamic IP addresses, use partial pattern
    i, r = get_client_ip(request, proxy_trusted_ips=('177.2.', '177.3.'))

नोट: इस नोटिस को पढ़ें ।


17
इसके स्रोत कोड पर एक नज़र डालें। यह अन्य उत्तरों द्वारा पहचानी गई सभी जटिलताओं को यहां संभालता है।
HostedMetrics.com

5
Thx @ हेलियोडोर - हां, मैंने औसत उपयोग के मामले के लिए मॉड्यूल को बहुत सरल बना दिया है और एक जटिल उपयोग के मामले के लिए बहुत लचीला है। न्यूनतम रूप से, आप अपना रोलअप करने से पहले इसके जीथब पृष्ठ को देखना चाहेंगे।
un33k

3
ध्यान दें कि django-ipware की सेटिंग्स डिफ़ॉल्ट रूप से सुरक्षित नहीं हैं! कोई भी एक अन्य चर पास कर सकता है और आपकी साइट उस आईपी को लॉग इन करेगी। हमेशा IPWARE_META_PRECEDENCE_LISTउस चर पर सेट करें जिसे आप उपयोग करते हैं, या pypi.python.org/pypi/WsgiUnproxy
vdboor

@vdboor क्या आप थोड़ा विस्तार कर सकते हैं? मैं रेपो में IPWARE_META_PRECEDENCE_LIST नहीं ढूँढ सकता।
मोनोलिथ

2
@ThaJay कृपया ध्यान दें कि 2.0.0 तक, आपको उपयोग करना चाहिए get_client_ip()get_real_ipहटा दिया गया है और 3.0 में हटा दिया जाएगा।
un33k

77

अलेक्जेंडर का जवाब बहुत अच्छा है, लेकिन कई बार आईपी के HTTP_X_FORWARDED_FOR हैडर में लौटने वाले परदे के पीछे की कमी है।

असली आईपी आमतौर पर सूची के अंत में होता है, जैसा कि यहाँ बताया गया है: http://en.wikipedia.org/wiki/X-Forwarded-For

समाधान सिकंदर के कोड का एक सरल संशोधन है:

def get_client_ip(request):
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        ip = x_forwarded_for.split(',')[-1].strip()
    else:
        ip = request.META.get('REMOTE_ADDR')
    return ip

5
हाँ, आईपी सूची की शुरुआत में है। यह यहां गलत है।
Pykler

4
दरअसल, यदि उपयोगकर्ता प्रॉक्सी के पीछे है तो आपको उपयोगकर्ता का आंतरिक आईपी पता, यानी RFC 1918 पता मिलेगा। ज्यादातर मामलों में, यह बहुत ही वांछनीय नहीं है। यह समाधान क्लाइंट के बाहरी आईपी पते (प्रॉक्सी पते) को प्राप्त करने पर केंद्रित है, जो सही-पता है।
सोवर

2
धन्यवाद। आमतौर पर जब मैं चाबियों का अनुरोध करता हूं तो मैं request.METAएक डिफ़ॉल्ट मान शामिल करता हूं क्योंकि हेडर अक्सर मिलिंग होते हैं:request.META.get('REMOTE_ADDR', None)
कार्ल जी

2
@CarlG आपका कोड अधिक पारदर्शी है, लेकिन प्राप्त विधि django.utils.datastructures.MultiValueDict से विरासत में मिली है और डिफ़ॉल्ट मान कोई नहीं है। लेकिन यह निश्चित रूप से एक डिफ़ॉल्ट मूल्य को शामिल करने के लिए समझ में आता है अगर आप वास्तव में चाहते थे कि यह कुछ भी नहीं के अलावा कुछ और हो।
सोवर

2
जब तक आप एक्स-फ़ॉर्वर्ड किए हुए नहीं होते हैं-जब अनुरोध आपके पहले सर्वर को हिट करते हैं, तो उस सूची में पहला मूल्य उपयोगकर्ता की आपूर्ति होता है । एक दुर्भावनापूर्ण उपयोगकर्ता आसानी से अपने इच्छित किसी भी आईपी पते को खराब कर सकता है। आपको जो पता चाहिए, वह आपके किसी भी सर्वर से पहले पहला आईपी है, जरूरी नहीं कि यह सूची में पहला हो।
एली

12

मैं यानचेन के उत्तर में सुधार का सुझाव देना चाहूंगा।

X_FORWARDED_FOR सूची में पहला आईपी लेने के बजाय, मैं पहला आंतरिक खाता लेता हूं जो ज्ञात आंतरिक आईपी नहीं है, क्योंकि कुछ राउटर प्रोटोकॉल का सम्मान नहीं करते हैं, और आप सूची के पहले मूल्य के रूप में आंतरिक ips देख सकते हैं।

PRIVATE_IPS_PREFIX = ('10.', '172.', '192.', )

def get_client_ip(request):
    """get the client ip from the request
    """
    remote_address = request.META.get('REMOTE_ADDR')
    # set the default value of the ip to be the REMOTE_ADDR if available
    # else None
    ip = remote_address
    # try to get the first non-proxy ip (not a private ip) from the
    # HTTP_X_FORWARDED_FOR
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        proxies = x_forwarded_for.split(',')
        # remove the private ips from the beginning
        while (len(proxies) > 0 and
                proxies[0].startswith(PRIVATE_IPS_PREFIX)):
            proxies.pop(0)
        # take the first ip which is not a private one (of a proxy)
        if len(proxies) > 0:
            ip = proxies[0]

    return ip

मुझे उम्मीद है कि इससे साथी गोगलर्स को मदद मिलेगी, जिनकी समस्या समान है।


यह कोड यह नहीं जांचता है कि HTTP_X_FORWARDED_FOR फ़ील्ड की जाँच करने से पहले REMOTE_ADDR से आईपी निजी है, क्योंकि यह संभवतः (भी, '127.0.0.1' या '127.') संभवतः PRIVATE_IPS_PREFIX में होना चाहिए, IPv6 समकक्षों के साथ
रसमस काज

1
तकनीकी रूप से, वे उपसर्ग (172, 192) जरूरी नहीं कि निजी पते हों।
maniexx

2
निजी नेटवर्कों के लिए निर्धारित पता श्रेणी हैं: 172.16.0.0–172.31.255.255 (16 "क्लास बी" नेटवर्क), 192.168.0.0–192.168.255.255 (1 "क्लास बी" नेटवर्क) और 10.0.0.0-10-10.255.255 (1) "क्लास ए" या 256 "क्लास बी" नेटवर्क)।
tzot

is_valid_ip परिभाषित नहीं है
प्रसेनजित

7

इसे पूरा करने के लिए यहां एक छोटा लाइनर है:

request.META.get('HTTP_X_FORWARDED_FOR', request.META.get('REMOTE_ADDR', '')).split(',')[0].strip()

3
अगर दोनों वापस नहीं आते हैं तो आपको एक त्रुटि मिलेगी।
गौरव चावला

6

सरलतम समाधान (यदि आप फास्टगि + निग्नेक्स का उपयोग कर रहे हैं) तो इटगोरिला ने क्या टिप्पणी की:

इस बेहतरीन सवाल के लिए धन्यवाद। मेरी Fastcgi REMOTE_ADDR मेटा कुंजी पास नहीं कर रही थी। मैंने नीचे nginx.conf में लाइन जोड़ी और समस्या को ठीक किया: fastcgi_param REMOTE_ADDR $ Remote_addr; - Itgorilla

Ps: मैंने इस उत्तर को सिर्फ उसके समाधान को अधिक दृश्यमान बनाने के लिए जोड़ा है।


1
नगनेक्स (रिवर्स प्रॉक्सी) और गॉम्नोर्न के लिए एक तुलनीय समाधान क्या है? proxy_set_header REMOTE_ADDR $remote_addr;nginx.conf में जोड़े जाने पर समस्या को कम नहीं करता है।
हसन बेग

6

नो मोर कन्फ्यूजन Django के हाल के संस्करणों में यह स्पष्ट रूप से उल्लेख किया गया है कि क्लाइंट का Ip पता उपलब्ध है

request.META.get("REMOTE_ADDR")

अधिक जानकारी के लिए Django डॉक्स की जाँच करें


5

मेरे मामले में, ऊपर दिए गए कार्यों में से कोई भी नहीं है, इसलिए मुझे uwsgi+ djangoस्रोत कोड की जांच करनी होगी और nginx में स्टेटिक पैराम को पास करना होगा और देखना होगा कि मैंने क्यों / कैसे, और नीचे क्या पाया है।

Env जानकारी:
अजगर संस्करण: 2.7.5
Django संस्करण: (1, 6, 6, 'final', 0)
nginx संस्करण: nginx/1.6.0
uwsgi:2.0.7

Env सेटिंग जानकारी:
nginx पोर्ट पर सुनने के विपरीत प्रॉक्सी80 uwsgi पर अपस्ट्रीम यूनिक्स सॉकेट के रूप में , अंततः अनुरोध का जवाब देगा

Django कॉन्फ़िगरेशन जानकारी:

USE_X_FORWARDED_HOST = True # with or without this line does not matter

नग्नेक्स विन्यास:

uwsgi_param      X-Real-IP              $remote_addr;
// uwsgi_param   X-Forwarded-For        $proxy_add_x_forwarded_for;
// uwsgi_param   HTTP_X_FORWARDED_FOR   $proxy_add_x_forwarded_for;

// hardcode for testing
uwsgi_param      X-Forwarded-For        "10.10.10.10";
uwsgi_param      HTTP_X_FORWARDED_FOR   "20.20.20.20";

django ऐप में सभी पारम्स प्राप्त करना:

X-Forwarded-For :       10.10.10.10
HTTP_X_FORWARDED_FOR :  20.20.20.20

निष्कर्ष:

तो मूल रूप से, आपको निगेन्क्स में ठीक उसी फ़ील्ड / परम नाम को निर्दिष्ट करना होगा, और उपयोग करना होगा request.META[field/param] django ऐप में ।

और अब आप तय कर सकते हैं कि एक मिडलवेयर (इंटरसेप्टर) को जोड़ना है या HTTP_X_FORWARDED_FORकुछ विचारों में सिर्फ पार्स करना है।


2

मूल रूप से Django से कार्यक्षमता को हटा दिए जाने का कारण यह था कि हेडर को अंततः भरोसा नहीं किया जा सकता है। कारण यह है कि इसे स्पूफ करना आसान है। उदाहरण के लिए nginx रिवर्स प्रॉक्सी को कॉन्फ़िगर करने के लिए अनुशंसित तरीका निम्न है:

add_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header X-Real-Ip       $remote_addr;

जब तुम करोगे:

curl -H 'X-Forwarded-For: 8.8.8.8, 192.168.1.2' http://192.168.1.3/

Myhost.com में आपका nginx आगे भेजेगा:

X-Forwarded-For: 8.8.8.8, 192.168.1.2, 192.168.1.3

X-Real-IPयदि आप निर्देश आँख बंद करके पालन पहले पिछले प्रॉक्सी के आईपी हो जाएगा।

इस बात पर भरोसा करने के लिए कि आपके उपयोगकर्ता कौन हैं एक समस्या है, आप कुछ इस तरह की कोशिश कर सकते हैं django-xff: https://pypi.python.org/pypi/django-xff/


1

मुझे उपर्युक्त उत्तर में प्रॉक्सी भी याद आ रही थी। मैंने django_easy_timezonesget_ip_address_from_request से उपयोग किया ।

from easy_timezones.utils import get_ip_address_from_request, is_valid_ip, is_local_ip
ip = get_ip_address_from_request(request)
try:
    if is_valid_ip(ip):
        geoip_record = IpRange.objects.by_ip(ip)
except IpRange.DoesNotExist:
    return None

और यहाँ विधि get_ip_address_from_request, IPv4 और IPv6 तैयार है:

def get_ip_address_from_request(request):
    """ Makes the best attempt to get the client's real IP or return the loopback """
    PRIVATE_IPS_PREFIX = ('10.', '172.', '192.', '127.')
    ip_address = ''
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '')
    if x_forwarded_for and ',' not in x_forwarded_for:
        if not x_forwarded_for.startswith(PRIVATE_IPS_PREFIX) and is_valid_ip(x_forwarded_for):
            ip_address = x_forwarded_for.strip()
    else:
        ips = [ip.strip() for ip in x_forwarded_for.split(',')]
        for ip in ips:
            if ip.startswith(PRIVATE_IPS_PREFIX):
                continue
            elif not is_valid_ip(ip):
                continue
            else:
                ip_address = ip
                break
    if not ip_address:
        x_real_ip = request.META.get('HTTP_X_REAL_IP', '')
        if x_real_ip:
            if not x_real_ip.startswith(PRIVATE_IPS_PREFIX) and is_valid_ip(x_real_ip):
                ip_address = x_real_ip.strip()
    if not ip_address:
        remote_addr = request.META.get('REMOTE_ADDR', '')
        if remote_addr:
            if not remote_addr.startswith(PRIVATE_IPS_PREFIX) and is_valid_ip(remote_addr):
                ip_address = remote_addr.strip()
    if not ip_address:
        ip_address = '127.0.0.1'
    return ip_address

0

Django.VERSION में (2, 1, 1, 'अंतिम', 0) अनुरोध हैंडलर

sock=request._stream.stream.raw._sock
#<socket.socket fd=1236, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.1.111', 8000), raddr=('192.168.1.111', 64725)>
client_ip,port=sock.getpeername()

यदि आप दो बार कोड से ऊपर कॉल करते हैं, तो आपको मिल सकता है

विशेषता ("'_ io.BytesIO' ऑब्जेक्ट में कोई विशेषता 'स्ट्रीम' नहीं है),)

AttributeError ("'LimitedStream' ऑब्जेक्ट का कोई गुण 'कच्चा' नहीं है")

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.