Open jcheng5 opened 11 years ago
Also HTTP request headers.
Has any movement happened on this? @jcheng5
@coatless No, but what did you need it for?
I have a shiny application that is setup to allow students to submit homework. The app right now only is able to record usernames and submission times on action submit. The request for IP addresses being passed to the shiny app is because it would enable me to store the user's IP along with the submitted assignment. This would provide additional evidence to support an academic integrity violation due to two submissions being ranked similarly under my current setup.
Another vote for exposing request IP
Yet another vote.
If your app is deployed using Connect or shinyapps.io, there's a bit of a hacky way to do this. We're working on making this less hacky by making it accessible from the server-side (and at all in shiny server), so this is not the final word on the topic. I just wanted to share what does work today if case it's useful for any of you:
library(shiny)
ui_xfwd <- NULL
ui <- function(req) {
if ("HTTP_X_FORWARDED_FOR" %in% ls(req)) ui_xfwd <<- req[["HTTP_X_FORWARDED_FOR"]]
fluidPage(
h3("result"),
uiOutput("result")
)
}
server <- function(input, output, session) {
output$result <- renderUI({
if (!is.null(ui_xfwd)) {
div(
p("HTTP_X_FORWARDED_FOR header present in UI:"),
p(ui_xfwd)
)
} else {
div(
p("HTTP_X_FORWARDED_FOR header not present; here's the REMOTE_ADDR:"),
p(session$request[["REMOTE_ADDR"]])
)
}
})
}
shinyApp(ui, server)
I wouldn't do it this way--I'll post a more robust workaround in a bit.
@jcheng5 any eta on the robust method?
Sorry for the delay. The problem with the method by @bborgesr is that it assumes that whenever the server function runs, the immediately preceding UI request was from the same browser. That's not necessarily true--it's entirely possible that those requests are not consecutive due to overlapping traffic or maybe the UI being cached when the user hits the back button.
If you're not too worried about fraud then a more reliable way to do this is to inject the IP address into the generated UI. I wish we had an input binding for <input type="hidden">
but we don't current have that, so you can hide a text input instead.
library(shiny)
ui <- function(req) {
fluidPage(
div(style = "display: none;",
textInput("remote_addr", "remote_addr",
if (!is.null(req[["HTTP_X_FORWARDED_FOR"]]))
req[["HTTP_X_FORWARDED_FOR"]]
else
req[["REMOTE_ADDR"]]
)
)
)
}
server <- function(input, output, session) {
cat("The remote IP is", isolate(input$remote_addr), "\n")
}
shinyApp(ui, server)
If you're more concerned about fraud then you'll unfortunately have to wait for the proper fix to land in our server products.
@jcheng5 is there an ETA on when the proper fix will land? (1 month, 6 months, year?)
@coatless Actually I took a closer look and this seems like it should already work with Shiny Server Pro (adding the following to /etc/shiny-server/shiny-server.conf
):
whitelist_headers "x-forwarded-for";
Then you could look for session$req$HTTP_X_FORWARDED_FOR
from within the server function.
This would be a good candidate for the next version of Shiny Server Open Source (cc @alandipert @shalutiwari) but there certainly will not be another release before rstudio::conf in early February. So at least a couple of months. Sorry I can't get more specific than that.
@jcheng5 excellent. A thousand thanks mate!
Never mind, the whitelist_headers
don't work--the codepath it operates on doesn't have the right headers in the first place. Let me see if I can figure this out.
Notes to self (and @alandipert):
xfwd
implementation for node-http-proxy is not ideal; see here. It doesn't preserve existing X-Forwarded-For
headers (if you're a proxy, you're supposed to append the remote-addr to the end of any existing X-Forwarded-For
header if the upstream proxy is trusted). Ideally we wouldn't use this but instead would implement these headers ourselves in lib/proxy/http.js
. Probably would want the administrator to tell us if the upstream proxy is trusted (or better yet, which IPs should be considered trusted proxies).X-Forwarded-*
for websocket is straightforward; SockJS allows these headers through. In lib/proxy/sockjs.js
, createWebSocketClient
can accept headers as its second argument, and you can get at the request headers via conn.$conn._conn.headers
(obviously we should add accessors instead of reading private fields).Any update on this? Exposing the request IP inside shiny would be quite useful.
Having access to the client's IP address would be really useful in my projects as well. Any chance we'll see this feature in an upcoming release?
If your app is deployed using Connect or shinyapps.io, there's a bit of a hacky way to do this. We're working on making this less hacky by making it accessible from the server-side (and at all in shiny server), so this is not the final word on the topic. I just wanted to share what does work today if case it's useful for any of you:
library(shiny) ui_xfwd <- NULL ui <- function(req) { ...
Is there a way to access the request information (even in a hacky way) from within a Shiny Module?
Is there a way to access the request information (even in a hacky way) from within a Shiny Module?
The approach suggested by @jcheng5 (https://github.com/rstudio/shiny/issues/141#issuecomment-351857670) should work from within a module (once it's fully supported)
I got the solution by @jcheng5 (https://github.com/rstudio/shiny/issues/141#issuecomment-352564869) to work by passing the request environment (req
in his code) through to the sub-module from the main ui function.
But now I'm seeing a value of 127.0.0.1, even when accessed from a different machine. Is this expected?
It seems that it is NOT expected, but it sometimes happens to users: https://groups.google.com/d/msg/shiny-discuss/9WcbS3E4Cfc/9hRS6VDyTxYJ
Does someone knows how to apply this solution using a apache reverse proxy?
If I run this solution on the RStudio server installed on my VM it works fine, but when I pass it to production, where I have a reverse proxy implemented, the IP is always 127.0.0.1
Any update on this? It would be great to be able to get clients' IP addresses to catch ineligible or fraudulent responses.
Has anyone tried session$req$HTTP_X_FORWARDED_FOR
on shinyapps.io recently?
Sorry for the delay. The problem with the method by @bborgesr is that it assumes that whenever the server function runs, the immediately preceding UI request was from the same browser. That's not necessarily true--it's entirely possible that those requests are not consecutive due to overlapping traffic or maybe the UI being cached when the user hits the back button.
If you're not too worried about fraud then a more reliable way to do this is to inject the IP address into the generated UI. I wish we had an input binding for
<input type="hidden">
but we don't current have that, so you can hide a text input instead.library(shiny) ui <- function(req) { fluidPage( div(style = "display: none;", textInput("remote_addr", "remote_addr", if (!is.null(req[["HTTP_X_FORWARDED_FOR"]])) req[["HTTP_X_FORWARDED_FOR"]] else req[["REMOTE_ADDR"]] ) ) ) } server <- function(input, output, session) { cat("The remote IP is", isolate(input$remote_addr), "\n") } shinyApp(ui, server)
If you're more concerned about fraud then you'll unfortunately have to wait for the proper fix to land in our server products.
Thanks @jcheng5 for this. I want to try to implement this in my shiny application. I've a just a quick question. What do you mean for "worried about fraud"? Is adding this function problematic on the users or developer side?
Thank you for your availability. I'll write back here as soon as I have a working example.
Are there any updates on this?
I'm another user of the open source server (https://shiny.psyctc.org/) and am on essentially zero budget providing free apps so I'm never going to be able to afford shiny server pro sadly. I would really like to see making the x-forwarded-for header available in the open source server (and ideally some guide as to how to process it!) Is it such a huge programming challenge?! TIA (and thanks for an amazing open source server though I do crave this!)
Need to look out for x-forwarded-for headers, talk to me for more info.